如何在nodejs里调用执行系统命令
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在nodejs里调用执行系统命令相关的知识,希望对你有一定的参考价值。
参考技术A 每种语言都有自己的优势,互相结合起来各取所长程序执行起来效率更高或者说哪种实现方式较简单就用哪个,nodejs是利用子进程来调用系统命令或者文件,文档见nodejs.org/api/child_process.html,NodeJS子进程提供了与系统交互的重要接口,其主要API有: 标准输入、标准输出及标准错误输出的接口。NodeJS 子进程提供了与系统交互的重要接口,其主要 API 有:
标准输入、标准输出及标准错误输出的接口
child.stdin 获取标准输入
child.stdout 获取标准输出
child.stderr 获取标准错误输出
获取子进程的PID:child.pid
提供生成子进程的方法:child_process.spawn(cmd, args=[], [options])
提供直接执行系统命令的方法:child_process.exec(cmd, [options], callback)
提供调用脚本文件的方法:child_process.execFile(file, [args], [options], [callback])
提供杀死进程的方法:child.kill(signal='SIGTERM')
用实例来感受一下,很有意思的,呵呵~~
1、利用子进程调用系统命令(获取系统内存使用情况)
新建nodejs文件,名为cmd_spawn.js,代码如下:
复制代码 代码如下:
var spawn = require('child_process').spawn;
free = spawn('free', ['-m']);
// 捕获标准输出并将其打印到控制台
free.stdout.on('data', function (data)
console.log('standard output:\n' + data);
);
// 捕获标准错误输出并将其打印到控制台
free.stderr.on('data', function (data)
console.log('standard error output:\n' + data);
);
// 注册子进程关闭事件
free.on('exit', function (code, signal)
console.log('child process eixt ,exit:' + code);
);本回答被提问者采纳
如何在节点中转义 shell 命令的字符串?
【中文标题】如何在节点中转义 shell 命令的字符串?【英文标题】:How do I escape a string for a shell command in node? 【发布时间】:2010-12-19 06:54:44 【问题描述】:在nodejs 中,执行外部命令的唯一方法是通过 sys.exec(cmd)。我想调用一个外部命令并通过标准输入给它数据。在nodejs中,似乎还没有一种方法可以打开命令然后将数据推送到它(仅用于执行并接收其标准+错误输出),所以我现在必须这样做的唯一方法是通过单个字符串命令,例如:
var dangerStr = "bad stuff here";
sys.exec("echo '" + dangerStr + "' | somecommand");
此类问题的大多数答案都集中在 nodejs(它使用 Google 的 V8 Javascript 引擎)中对我不起作用的正则表达式或 Python 等其他语言的本机功能。
我想逃避 dangerStr 以便可以安全地编写像上面那样的 exec 字符串。如果有帮助,dangerStr 将包含 JSON 数据。
【问题讨论】:
对于 Bourne 类型的 shell,您可以使用以下算法安全地转义字符串:1) 将所有出现的单引号 (') 替换为四个字符序列单引号、反斜杠、单引号、单引号('\'') 2) 在修改后的字符串的开头和结尾添加一个额外的单引号。前导单引号和尾随单引号的编码效率不高,但它仍然有效——当它可能只是 \' 时,' 变成了 ''\'''。 为了澄清:我花了一点时间来理解@ChrisJohnsen 的建议,但它检查出来了。如果您想在 shell 上使用don't do that
,请使用echo 'don'\''t do that'
生成don't do that
。
在python中,这里实现github.com/python/cpython/blob/…
嗯,这是很久以后的事了,不过你也可以使用child_process
模块...
【参考方案1】:
这是我用的:
var escapeShell = function(cmd)
return '"'+cmd.replace(/(["'$`\\])/g,'\\$1')+'"';
;
【讨论】:
@DavidTorresabc$abc
变为 abc\$abc
如果使用撇号'
,则无需转义$
这似乎是错误的:它将foo bar
转义为"foo\ bar"
,将被解析为foo\ bar
。
如果将所有内容都用双引号括起来,则不需要引用空格 (\s
),因为这会自动保留所有空格。如果字符串周围没有引号,您只需要这样做,否则空格会被 shell 视为参数分隔符。此外,当您将制表符转换为 \
时,您也没有正确引用空格,但正确的形式是 \t
。
这似乎是命令注入和奇怪的边缘案例问题的邀请。【参考方案2】:
如果您需要简单(但正确)的解决方案,您可以使用:
function escapeShellArg (arg)
return `'$arg.replace(/'/g, `'\\''`)'`;
因此,正如 Chris Johnsen 所提到的,您的字符串将简单地用单引号转义。
echo 'John'\''s phone';
由于strong quoting,它在bash
中有效,感觉在fish
中也有效,但在zsh
和sh
中无效。
如果您有bash
,您可以在sh
或zsh
和'bash -c \'' + escape('all-the-rest-escaped') + '\''
中运行您的脚本。
但实际上... node.js 会为您转义所有需要的字符:
var child = require('child_process')
.spawn('echo', ['`echo 1`;"echo $SSH_TTY;\'\\00..5']);
child.stdout.on('data', function (data)
console.log('stdout: ' + data);
);
child.stderr.on('data', function (data)
console.log('stderr: ' + data);
);
这段代码将执行:
echo '`echo 1`;"echo $SSH_TTY;'\''\\00..5'
会输出:
stdout: `echo 1`;"echo $SSH_TTY;\'\\00..5
或一些错误。
看看http://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options
顺便说一句,运行一堆命令的简单解决方案是:
require('child_process')
.spawn('sh', ['-c', [
'cd all/your/commands',
'ls here',
'echo "and even" > more'
].join('; ')]);
祝你有美好的一天!
【讨论】:
【参考方案3】:你should never rely on escaping unknown input going to a shell parameter - 几乎总会有一些你没有想到的极端情况允许用户在你的服务器上执行任意代码。
Node 支持调用命令并分别传递每个参数,无需转义。这是最安全的方法:
const spawn = require('child_process');
// Note that the arguments are in an array, not using string interpolation
const ls = spawn('ls', ['-lh', '/usr']);
ls.stdout.on('data', (data) =>
console.log(`stdout: $data`);
);
ls.stderr.on('data', (data) =>
console.log(`stderr: $data`);
);
ls.on('close', (code) =>
console.log(`child process exited with code $code`);
);
文档是here
【讨论】:
【参考方案4】:我赞同Will的意见,尽可能避免用手逃跑,更喜欢spawn。
但是,在无法避免转义的情况下,例如如果您需要使用 exec 或者您是 executing a command through ssh。然后你可以使用base64将安全字符传递给bash,并依靠bash来逃避未知。
const dangerStr = 'bad stuff here'
// base64 has safe characters [A-Za-z=0-9+/]
const dangerBase64 = btoa(dangerStr)
sys.exec(`echo "$(echo $dangerBase64 | base64 -d)" | somecommand`)
解释如下:
dangerBase64
未知,但它不包含bash 中的不安全字符。因此echo $dangerBase64
会输出我们想要的。
最后,$(echo $dangerBase64 | base64 -d)
周围的双引号转义了用户在 bash 中传递的实际值,这是安全的,并且与用户想要的值相同。
【讨论】:
【参考方案5】:如果您还需要处理特殊字符(换行符等),您可以这样做:
str = JSON.stringify(str)
.replace(/^"|"$/g,'') //remove JSON-string double quotes
.replace(/'/g, '\'"\'"\'') //escape single quotes the ugly bash way
这假设您通过单引号使用 Bash 的 strong-quoting)并且接收者可以理解 JSON 的类似 C 的转义。
【讨论】:
【参考方案6】:如果您正在构建自己的软件,您可以将命令编码为 base64 或十六进制格式,然后从程序中解码参数。
对于我使用的 Nodejs 应用程序。
var base64_encode = exports.base64_encode = function(non_base64_string)
return Buffer.from(non_base64_string).toString('base64');
var base64_decode = exports.base64_decode = function(base64_string)
return Buffer.from(base64_string, 'base64').toString('ascii')
所以当我运行这样的 base64 编码命令时
webman grep --search "aW5jbHVkZV9vbmNlICRfU0VSVkVSWyJET0NVTUVOVF9ST09UIl0uIi9zZXR0aW5ncy5waHAiOw==" --replacement "JGRvY3VtZW50X3Jvb3QgPSBfX0RJUl9fO3doaWxlKHRydWUpe2lmIChmaWxlX2V4aXN0cygkZG9jdW1lbnRfcm9vdC4iL3NldHRpbmdzLmpzb24iKSl7YnJlYWs7fWVsc2V7JGRvY3VtZW50X3Jvb3Q9ZGlybmFtZSgkZG9jdW1lbnRfcm9vdCk7fX08bmV3bGluZT5pbmNsdWRlX29uY2UgJGRvY3VtZW50X3Jvb3QuIi9zZXR0aW5ncy5waHAiOw=="
我可以使用base64_decode
毫无压力地获取参数search
和replacement
参数
【讨论】:
【参考方案7】:有一种写入外部命令的方法:process.createChildProcess
(documentation) 使用write
方法返回一个对象。 createChildProcess
不太方便,因为它不缓冲 stdout 和 stderr,所以你需要事件处理程序来读取块中的输出。
var stdout = "", stderr = "";
var child = process.createChildProcess("someCommand");
child.addListener("output", function (data)
if (data !== null)
stdout += data;
);
child.addListener("error", function (data)
if (data !== null)
stderr += data;
);
child.addListener("exit", function (code)
if (code === 0)
sys.puts(stdout);
else
// error
);
child.write("This goes to someCommand's stdin.");
【讨论】:
有趣.. 谢谢!顺便说一句,新的 URI 是 nodejs.org/api/child_process.html 你没有解释任何关于转义参数的事情。 这并不能回答 OP 所询问的内容,即转义参数。echo
的使用只是一个例子。 OP 不只是试图将字符串传递给命令。他们试图在命令行中使用任意字符串。
它没有回答标题中的问题,但这通过完全避免问题来解决问题。 OP 接受了答案,所以显然它有所帮助。以上是关于如何在nodejs里调用执行系统命令的主要内容,如果未能解决你的问题,请参考以下文章