据我所知,官方 ECMAScript 规范中没有内置函数、方法或其他方式来运行外部进程。也就是说,允许扩展,参见规范中的this note,例如:
注意内置函数的示例包括 parseInt 和 Math.exp。一种
主机或实现可以提供额外的内置功能,
本规范中没有描述。
这样的“主机”之一是 Node.js,它具有 child_process 模块。让我们试试这段代码执行Linux shell命令ps -aux,保存在runps.js,基于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}`);
});
这会产生以下示例输出,在 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 install ...。
如果您在 github 中的 Node.js 代码中搜索 spawn,您将在引擎中的 C 或 C++ 中找到对 implementation 的引用。出于明显的安全原因,Firefox 和 Chrome 等现代浏览器不愿意使用这些功能扩展 JavaScript,即使 V8 等底层引擎支持它也是如此。
请注意,最好不要以 root 身份运行我们的容器,让我们再次尝试上面的示例,这次添加 random user。
$ 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 版本仍然有 Windows Script Host,它可以使用 wscript.exe 或 cscript.exe 程序在控制台上运行 JScript,即不需要浏览器。要试用它,您可以打开 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
其中显示以下内容并打开 Paint:
Microsoft (R) Windows Script Host Version 5.812
Copyright (C) Microsoft Corporation. All rights reserved.
Hallo, ECMAScript on Windows!
存在其他变体。查找适用于您首选 JavaScript runtime environment 的文档。