child_process.exec()执行含空格Git命令时stdout为空的原因
为什么Node.js中exec执行带空格的git format命令无输出?
我在JavaScript文件中编写了以下代码并通过Node.js运行:
var exec = require('child_process').exec; var child; child = exec("git for-each-ref --format='%(committerdate), %(authorname)' --sort=committerdate --merged develop", function (error, stdout, stderr) { console.log('stdout: ' + stdout); console.log('typeof stdout: ' + typeof stdout); console.log('stderr: ' + stderr); if (error !== null) { console.log('exec error: ' + error); } });
执行后仅得到空字符串作为stdout,无任何错误信息:
stdout: stderr:
但如果移除%(committerdate), %(authorname)中逗号后的空格,就能得到预期输出,可正常运行的代码如下:
var exec = require('child_process').exec; var child; child = exec("git for-each-ref --format='%(committerdate),%(authorname)' --sort=committerdate --merged develop", function (error, stdout, stderr) { console.log('stdout: ' + stdout); console.log('stderr: ' + stderr); if (error !== null) { console.log('exec error: ' + error); } });
奇怪的是,直接在PowerShell或Git Bash中运行带空格的命令均可正常输出:
git for-each-ref --format='%(committerdate), %(authorname)' --sort=committerdate --merged develop
环境信息:
- Windows 10
- Node.js 16.7.0
原因分析
问题出在Windows下child_process.exec默认使用cmd.exe执行命令,而cmd对单引号的处理和PowerShell/Git Bash完全不同:
- 在PowerShell/Git Bash中,单引号会被当作字符串边界,
--format='%(committerdate), %(authorname)'会被解析为一个完整的参数传递给git。 - 但在cmd中,单引号不具备字符串边界的作用,空格会被直接当作参数分隔符。这导致git实际收到的
--format参数是%(committerdate),,而后面的%(authorname)被当成了一个独立的、git无法识别的参数,最终没有输出结果。
当去掉逗号后的空格时,%(committerdate),%(authorname)是一个无空格的整体,cmd不会拆分它,git能正确拿到完整的format模板,因此可以正常输出。
解决办法
有两种可靠的解决方式:
改用双引号包裹format参数
在cmd中双引号可以作为字符串边界,因此把命令中的单引号换成双引号(注意转义字符串内部的双引号):child = exec("git for-each-ref --format=\"%(committerdate), %(authorname)\" --sort=committerdate --merged develop", ...);使用
execFile替代execexecFile不会通过shell解析命令,而是直接将参数数组传递给目标程序,彻底避免shell解析带来的问题:var execFile = require('child_process').execFile; execFile('git', [ 'for-each-ref', '--format=%(committerdate), %(authorname)', '--sort=committerdate', '--merged', 'develop' ], function(error, stdout, stderr) { console.log('stdout: ' + stdout); console.log('stderr: ' + stderr); if (error !== null) { console.log('exec error: ' + error); } });
内容的提问来源于stack exchange,提问作者Phalgun
相关产品推荐
相关产品推荐

