How to execute shell commands in JavaScript
Asked Answered
L

16

223

I want to write a JavaScript function which will execute the system shell commands (ls for example) and return the value.

How do I achieve this?

Lazos answered 10/12, 2009 at 10:54 Comment(3)
where would you like to execute this command, on the client or on the server?Aquatint
Why did you choose the most disliked answer as the best answer? o.0Searby
For anyone who wants to execute a command on button click, check the next.js way here: #71647484Harness
L
193

I'll answer assuming that when the asker said "Shell Script" he meant a Node.js backend JavaScript. Possibly using commander.js to use frame your code :)

You could use the child_process module from node's API. I pasted the example code below.

var exec = require('child_process').exec;

exec('cat *.js bad_file | wc -l',
    function (error, stdout, stderr) {
        console.log('stdout: ' + stdout);
        console.log('stderr: ' + stderr);
        if (error !== null) {
             console.log('exec error: ' + error);
        }
    });
Lulu answered 17/12, 2013 at 15:33 Comment(4)
Except for one thing. You'll get the error "child is not a function". The call to exec() executes the command - no need to call child(). Unfortunately, the callback isn't called whenever the child process has something to output - it is called only when the child process exits. Sometimes that's OK and sometimes it's not.Chimney
To avoid callbacks, you can use execSync.Jointless
Who talked about a browser ? It only says JavaScript, nothing more.Shutter
@Lulu How to pass credentials here (user name and password)?Spradlin
J
143

I don't know why the previous answers gave all sorts of complicated solutions. If you just want to execute a quick command like ls, you don't need async/await or callbacks or anything. Here's all you need - execSync:

const execSync = require('child_process').execSync;
// import { execSync } from 'child_process';  // replace ^ if using ES modules

const output = execSync('ls', { encoding: 'utf-8' });  // the default is 'buffer'
console.log('Output was:\n', output);

For error handling, add a try/catch block around the statement.

If you're running a command that takes a long time to complete, then yes, look at the asynchronous exec function.

Jointless answered 30/9, 2018 at 6:6 Comment(3)
Does execSync works with Mac, Linux and Windows commands?Tomblin
Confirmed for windows. Also, I see that there's a shell option for specifying "Shell to execute the command with." Default: '/bin/sh' on Unix, process.env.ComSpec on Windows.Gynaeceum
Please do not use synchronous external operations, because your server will not be able to serve other requests until it is finished.Cocklebur
N
74

...few year later...

ES6 has been accepted as a standard and ES7 is around the corner so it deserves updated answer. We'll use ES6+async/await with nodejs+babel as an example, prerequisites are:

Your example foo.js file may look like:

import { exec } from 'child_process';

/**
 * Execute simple shell command (async wrapper).
 * @param {String} cmd
 * @return {Object} { stdout: String, stderr: String }
 */
async function sh(cmd) {
  return new Promise(function (resolve, reject) {
    exec(cmd, (err, stdout, stderr) => {
      if (err) {
        reject(err);
      } else {
        resolve({ stdout, stderr });
      }
    });
  });
}

async function main() {
  let { stdout } = await sh('ls');
  for (let line of stdout.split('\n')) {
    console.log(`ls: ${line}`);
  }
}

main();

Make sure you have babel:

npm i babel-cli -g

Install latest preset:

npm i babel-preset-latest

Run it via:

babel-node --presets latest foo.js
Naker answered 8/8, 2015 at 19:48 Comment(3)
If you only need to execute a quick command, all the async/await is overkill. You can just use execSync.Jointless
No one asked for a Node.js solution. It only says JavaScript.Shutter
@Virus721: in which JavaScript runtime do you want to execute a shell command?Jointless
G
33

This depends entirely on the JavaScript environment.

For example, in Windows Scripting, you do things like:

var shell = WScript.CreateObject("WScript.Shell");
shell.Run("command here");
Gyroscope answered 10/12, 2009 at 10:58 Comment(4)
Is it possible to do the same thing in a Unix-like operating system such as Linux?Grammalogue
That's what I was looking for. It's annoying all those people talking about their Node.js. Who asked for Node.js here ? No one did.Shutter
Would you know how to get some result (say, exit code), of the newly run command?Aurangzeb
@Aurangzeb I answered this nearly 14 years ago, can't say I've kept up with WScript. But the docs say the Run() method returns the exit code. vbsedit.com/html/6f28899c-d653-4555-8a59-49640b0e32ea.aspGyroscope
T
21

In a nutshell:

// Instantiate the Shell object and invoke its execute method.
var oShell = new ActiveXObject("Shell.Application");

var commandtoRun = "C:\\Winnt\\Notepad.exe";
if (inputparms != "") {
  var commandParms = document.Form1.filename.value;
}

// Invoke the execute method.  
oShell.ShellExecute(commandtoRun, commandParms, "", "open", "1");
Takahashi answered 10/12, 2009 at 10:58 Comment(2)
ActiveXObject is available only on IE browser.Smitt
There seems to be a lot of hand-wringing over which web browser this is running in, but folks should realize that JavaScript is also a perfectly valid Windows shell scripting language.Depose
P
9
function exec(cmd, handler = function(error, stdout, stderr){console.log(stdout);if(error !== null){console.log(stderr)}})
{
    const childfork = require('child_process');
    return childfork.exec(cmd, handler);
}

This function can be easily used like:

exec('echo test');
//output:
//test

exec('echo test', function(err, stdout){console.log(stdout+stdout+stdout)});
//output:
//testtesttest
Placate answered 27/4, 2019 at 17:25 Comment(1)
For some reason the commands are executed from the end. For example, the commands exec('echo 1'); exec('echo 2'); exec('echo 3'); exec('echo 4'); will lead to the conclusion 4 3 2 1Jiminez
U
8

Note: These answers are from a browser-based client to a Unix-based web server.

Run a command on the client

You essentially can't. Security says only run within a browser and its access to commands and filesystem is limited.

Run 'ls' on the server

You can use an Ajax call to retrieve a dynamic page, passing in your parameters via a GET.

Be aware that this also opens up a security risk as you would have to do something to ensure that Mrs rouge hacker does not get your application to say run: /dev/null && rm -rf / ...

So in a nutshell, running from JavaScript is just a bad, bad idea... your mileage may vary.

Ufa answered 10/12, 2009 at 11:3 Comment(2)
You essentially can't in a cross-browser manner. I believe only IE has hooks into the shell (via WSript/ActiveX).Triage
All the high vote answers assume it's run in a non-browser context, e.g. Node. The right thing is to clarify the question, not this answer.Barrows
E
8

With NodeJS is simple like that! And if you want to run this script at each boot of your server, you can have a look on the forever-service application!

var exec = require('child_process').exec;

exec('php main.php', function (error, stdOut, stdErr) {
    // do what you want!
});
Embryotomy answered 7/12, 2016 at 2:31 Comment(2)
To avoid callbacks, for quick commands you can use execSync.Jointless
what if want to run sudo mysql .?? is it possible ?? if yes, how the password, it is going to ask after this command.Karli
S
5

Here is simple command that executes ifconfig shell command of Linux

var process = require('child_process');
process.exec('ifconfig',function (err,stdout,stderr) {
    if (err) {
        console.log("\n"+stderr);
    } else {
        console.log(stdout);
    }
});
Suppositious answered 16/9, 2015 at 8:6 Comment(1)
To avoid callbacks, you can use execSync.Jointless
D
4

As far as I can tell, there is no built-in function, method or otherwise, in the official ECMAScript specification to run an external process. That said, extensions are allowed, see this note from the spec, for example:

NOTE Examples of built-in functions include parseInt and Math.exp. A host or implementation may provide additional built-in functions that are not described in this specification.

One such "host" is Node.js which has the child_process module. Let's try this code to execute the Linux shell command ps -aux, saved in runps.js, based on the child_process documentation:

const { spawn } = require('child_process');
const ps = spawn('ps', ['-aux']);

ps.stdout.on('data', (data) => {
  console.log(`stdout: ${data}`);
});

ps.stderr.on('data', (data) => {
  console.error(`stderr: ${data}`);
});

ps.on('close', (code) => {
  console.log(`child process exited with code ${code}`);
});

Which produces the following example output, running it in docker:

$ docker run --rm -v "$PWD":/usr/src/app -w /usr/src/app node:17-bullseye node ./runps.js
stdout: USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.0  0.8 319312 33888 ?        Ssl  11:08   0:00 node ./runps.js
root          13  0.0  0.0   6700  2844 ?        R    11:08   0:00 ps -aux

child process exited with code 0

The thing I like about this module, is that it's included with the Node.js distribution, no npm install ... needed.

If you search the Node.js code in github for spawn you will find references to the implementation in C or C++ in the engine. Modern browsers like Firefox and Chrome would be reluctant to extend JavaScript with such features, for obvious security reasons, even if the underlying engine such as V8 supports it.

On that note, it's better not to run our container as root, let's try the above example again, adding a random user this time.

$ docker run --rm -u 7000 -v "$PWD":/usr/src/app -w /usr/src/app node:17-bullseye node ./runps.js
stdout: USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
7000           1  5.0  0.8 319312 33812 ?        Ssl  11:19   0:00 node ./runps.js
7000          13  0.0  0.0   6700  2832 ?        R    11:19   0:00 ps -aux

child process exited with code 0

Of course that's better but not enough. If this approach is used at all, more precautions must be taken, such as ensuring that no arbitrary user commands can be executed.

Windows 10

My version of Windows 10 still has Windows Script Host which can run JScript on the console with the wscript.exe or cscript.exe programs, i.e. no browser needed. To try it out you can open a PowerShell Windows Terminal. Save the following code into a file which you can call shell.js:

WScript.StdOut.WriteLine("Hallo, ECMAScript on Windows!");
WScript.CreateObject("WScript.Shell").run("C://Windows//system32//mspaint.exe");

And on the command line, run:

cscript .\shell.js

Which shows the following and opens Paint:

Microsoft (R) Windows Script Host Version 5.812
Copyright (C) Microsoft Corporation. All rights reserved.

Hallo, ECMAScript on Windows!

Other variations exist. Find the documentation applicable to your preferred JavaScript runtime environment.

Dramaturge answered 11/11, 2021 at 11:26 Comment(0)
F
3

If you are using npm you can use the shelljs package

To install: npm install [-g] shelljs

var shell = require('shelljs');
shell.ls('*.js').forEach(function (file) {
// do something
});

See more: https://www.npmjs.com/package/shelljs

Fulgurate answered 4/5, 2020 at 4:55 Comment(0)
C
2

Another post on this topic with a nice jQuery/Ajax/PHP solution:

shell scripting and jQuery

Caritta answered 5/4, 2012 at 18:37 Comment(1)
the question specifies javascript.Barrows
G
2

In IE, you can do this :

var shell = new ActiveXObject("WScript.Shell");
shell.run("cmd /c dir & pause");
Graiae answered 21/3, 2014 at 7:18 Comment(1)
ActiveXObject is available only for IE browser.Barrows
B
1

With nashorn you can write a script like this:

$EXEC('find -type f');
var files = $OUT.split('\n');
files.forEach(...
...

and run it:

jjs -scripting each_file.js
Benoit answered 6/12, 2016 at 19:37 Comment(0)
R
0
const fs = require('fs');

function ls(startPath) {
    fs.readdir(startPath, (err, entries) => {
        console.log(entries);
    })
}

ls('/home/<profile_name>/<folder_name>')

The startPath used here is in reference with debian distro

Rootless answered 6/10, 2022 at 15:28 Comment(0)
F
0

Js file

var oShell = new ActiveXObject("Shell.Application");
oShell.ShellExecute("E:/F/Name.bat","","","Open","");

Bat file

powershell -Command "& {ls | Out-File -FilePath `E:F/Name.txt}"`

Js file run with node namefile.js

const fs = require('fs')

fs.readFile('E:F/Name.txt', (err, data) => {
if (err) throw err;

console.log(data.toString());
})

You can also do everything in one solution with an asynchronous function. Directly there could be security problems.

Fantasm answered 16/2, 2023 at 15:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.