如何在JavaScript中执行shell命令

220
我想编写一个JavaScript函数,它可以执行系统shell命令(例如ls)并返回结果值。
我该如何实现这个功能?

5
您希望在客户端还是服务器上执行此命令? - Jan Hančič
8
为什么您选择了最不受欢迎的答案作为最佳答案?o.0 - André Levy
对于任何想在按钮点击时执行命令的人,可以在这里查看next.js的方式: https://dev59.com/vLb3oIgBc1ULPQZF8tfb - user1506104
16个回答

193

假设问者所说的“Shell Script”是指使用Node.js作为后端JavaScript,可能会使用commander.js框架来编写代码 :)

您可以使用来自node API的child_process模块。我在下面粘贴了示例代码。

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);
        }
    });

23
除了一件事。你会得到“child不是一个函数”的错误。调用exec()执行命令,不需要调用child()。不幸的是,回调函数仅在子进程退出时才被调用,而不是在子进程有输出时被调用。有时候这样做没问题,有时候就不行。 - John Deighan
7
为避免回调函数,您可以使用execSync - Dan Dascalescu
3
谁谈论了浏览器?它只是提到了JavaScript,没有更多的信息。 - Virus721
@Josh 在这里如何传递凭据(用户名和密码)? - Shabar

138

我不知道为什么之前的答案都提供了各种复杂的解决方案。如果您只想执行像 ls 这样的快速命令,您不需要异步/等待或回调或任何其他东西。这就是您需要的全部内容 - 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);

为了进行错误处理,请在语句周围添加 try/catch 块。

如果您正在运行需要很长时间才能完成的命令,则可以查看异步 exec 函数。


4
execSync能够运行Mac、Linux和Windows命令吗? - Naazneen Jatu
已确认适用于Windows。此外,我看到有一个“shell”选项可用于指定“执行命令的Shell”。默认值为Unix上的'/bin/sh',在Windows上为process.env.ComSpec。 - Kerry Randolph
请不要使用同步的外部操作,因为这会导致您的服务器在完成操作之前无法处理其他请求。 - sarkiroka

72

...几年后...

ES6已被接受为标准,ES7也即将到来,因此这篇文章值得更新。我们将使用ES6+async/await与nodejs+babel作为示例,前提是:

您的示例foo.js文件可能如下所示:

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();

确保您已安装Babel:

npm i babel-cli -g

安装最新预设:

npm i babel-preset-latest

通过以下方式运行:

babel-node --presets latest foo.js

5
如果你只需要执行一个快速命令,所有的 async/await 就显得有些过度了。你可以直接使用 execSync - Dan Dascalescu
4
没有人要求使用Node.js解决方案,只是说JavaScript。 - Virus721
7
你希望在哪个JavaScript运行时环境中执行一个shell命令? - Dan Dascalescu

33
这完全取决于JavaScript环境。
例如,在Windows Scripting中,你可以做如下操作:
var shell = WScript.CreateObject("WScript.Shell");
shell.Run("command here");

21
在类Unix操作系统如Linux中,能否做到同样的事情? - Anderson Green
10
这正是我在寻找的。所有那些谈论他们的Node.js的人都很烦人。这里有谁要求使用Node.js吗?没有人。 - Virus721
你知道如何获取新运行命令的某些结果(例如退出代码)吗? - sighclone
@sighclone,我在近14年前回答过这个问题,不能说我一直跟上了WScript的发展。但是文档显示Run()方法返回退出代码。https://www.vbsedit.com/html/6f28899c-d653-4555-8a59-49640b0e32ea.asp - Matt

21

简而言之:

// 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");

11
ActiveXObject 仅在 IE 浏览器上可用。 - Christopher Markieta
7
有很多人似乎在纠结这个程序是在哪个网络浏览器中运行,但他们应该意识到JavaScript也是一种完全有效的Windows shell脚本语言。 - Craig Tullis
3
不熟悉那个特定的"NutShell" shell ;) - redevill

8
注意:这些答案来自基于浏览器的客户端到基于Unix的Web服务器的交互。
在客户端上运行命令是不可能的。安全性要求只能在浏览器内部运行,其访问命令和文件系统的权限受到限制。
在服务器上运行ls命令,您可以使用AJAX调用检索动态页面,并通过GET传递参数。
请注意,这也会带来安全风险,因为您必须确保黑客无法通过您的应用程序运行/dev/null && rm -rf /等危险指令。
总之,从JS中运行命令只是一个非常糟糕的想法......可能会有所不同。

你基本上无法以跨浏览器的方式实现这一点。我相信只有IE可以通过WSript/ActiveX钩子进入shell。 - Justin Johnson
1
所有高票答案都假定它在非浏览器上下文中运行,例如Node。正确的做法是澄清问题,而不是这个答案。 - Inigo

8
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);
}

这个函数可以轻松地使用,例如:

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

exec('echo test', function(err, stdout){console.log(stdout+stdout+stdout)});
//output:
//testtesttest

8

使用NodeJS就像这样简单!如果你想在每次启动服务器时运行此脚本,可以查看forever-service应用程序!

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

exec('php main.php', function (error, stdOut, stdErr) {
    // do what you want!
});

1
为了避免回调,对于快速命令,您可以使用 execSync - Dan Dascalescu
如果想运行 sudo mysql,有什么办法吗? 这是可能的吗? 如果是,那么在执行此命令后,它将要求输入密码。 - Aman Deep

5

这里是执行Linux的ifconfig shell命令的简单命令。

var process = require('child_process');
process.exec('ifconfig',function (err,stdout,stderr) {
    if (err) {
        console.log("\n"+stderr);
    } else {
        console.log(stdout);
    }
});

为了避免回调,您可以使用 execSync - Dan Dascalescu

4
据我所知,在官方ECMAScript规范中,没有内置的函数、方法或其他方式来运行外部进程。不过,规范允许扩展,例如this note所示:

注意:内置函数的示例包括parseInt和Math.exp。主机或实现可能提供其他未在本规范中描述的内置函数。

其中一个“主机”是Node.js,它有child_process模块。根据child_process文档,我们尝试使用以下代码执行Linux shell命令ps -aux,保存在runps.js中:
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}`);
});

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

我喜欢这个模块的原因是它已经包含在Node.js分发版中,不需要进行npm安装。
如果你在github上搜索Node.js代码中的spawn,你会发现引用了C或C++实现的引擎。现代浏览器,如Firefox和Chrome,出于明显的安全原因,即使底层引擎(如V8)支持,也不愿意扩展JavaScript的这种功能。
在这个基础上,最好不要以 root 权限运行我们的容器,让我们再次尝试上面的示例,这次添加一个 随机用户
$ 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

当然,这样做更好,但还不够。如果使用这种方法,必须采取更多的预防措施,例如确保不会执行任意用户命令。
Windows 10
我的 Windows 10 版本仍然拥有可以在控制台上运行 JScript 的 Windows Script Host,无需浏览器。要尝试它,您可以打开 PowerShell Windows Terminal。将以下代码保存到一个名为 shell.js 的文件中:
WScript.StdOut.WriteLine("Hallo, ECMAScript on Windows!");
WScript.CreateObject("WScript.Shell").run("C://Windows//system32//mspaint.exe");

在命令行上运行以下命令:
cscript .\shell.js

这句话的意思是:“显示以下内容并打开画图程序:”。
Microsoft (R) Windows Script Host Version 5.812
Copyright (C) Microsoft Corporation. All rights reserved.

Hallo, ECMAScript on Windows!

其他变体也存在。请查找适用于您首选的JavaScript 运行环境 的文档。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接