终端可正常运行的Git地址转换Shell脚本在JavaScript exec()中执行报错的排查与解决
解决JS exec调用Git地址转换Shell命令的报错问题
你的问题核心是JavaScript字符串的转义规则和Shell的转义规则冲突,导致传递给sed的表达式被破坏,进而触发sed的语法错误。咱们一步步拆解问题并解决:
问题根源分析
先看报错信息:sed: -e expression #1, char 6: unknown option to 's',这说明sed收到的替换表达式格式完全错乱了。
你在终端里能正常执行的命令,到了JS模板字符串里会被JS先解析一遍转义字符:
- 你写的
\/在JS模板字符串中会被直接解析成单个/ - 所以原本的
"s:/\//g"经过JS处理后,变成了"s://g" - 而sed的
s命令格式是s<分隔符>查找<分隔符>替换<分隔符>标志,你用:当分隔符的话,s://g会被sed理解为语法错误的替换命令,自然报错。
排查小技巧
在调用exec之前,先把生成的命令打印出来,就能直观看到问题:
const cmd = `echo git@github.com:hasantezcan/journey-of-2021.git | sed -e "s:/\//g" -e "s:ssh\/\/\///g" -e "s:git@:https:\/\//g"`; console.log(cmd);
你会发现输出的命令里,所有\/都变成了/,和你在终端里手动输入的命令完全不一样——这就是问题的核心。
解决方法
推荐两种方案,优先选第一种,更简洁不易出错:
方案1:更换sed的分隔符,避免和/冲突
sed的s命令支持用任意非空格字符作为分隔符,比如#或@,这样替换字符串里的/就不需要转义,JS也不会乱解析。
你的需求是把SSH格式的Git地址转成HTTPS格式,其实只需要两个关键替换:
- 把
git@替换成https:// - 把域名后的
:替换成/
修改后的JS代码:
await exec( `echo git@github.com:hasantezcan/journey-of-2021.git | sed -e "s#git@#https://#" -e "s#:#/#"`, (error, stdout, stderr) => { console.log("linux test"); console.log("------error: ", error); console.log("++++++stdout: ", stdout); console.log("```````stderr: ", stderr); } );
这样既简化了命令,又完全避免了转义冲突。
方案2:正确处理JS的转义序列
如果你坚持用:作为分隔符,需要把JS里的\再转义一次(写成\\),这样JS解析后会向Shell传递一个真实的\,让sed能正确识别转义的/。
修改后的代码:
await exec( `echo git@github.com:hasantezcan/journey-of-2021.git | sed -e "s:\\/\\//g" -e "s:ssh\\/\\/\\/\\//g" -e "s:git@:https:\\/\\//g"`, (error, stdout, stderr) => { console.log("linux test"); console.log("------error: ", error); console.log("++++++stdout: ", stdout); console.log("```````stderr: ", stderr); } );
不过这种方法需要处理多层转义,容易出错,不推荐。
内容的提问来源于stack exchange,提问作者Hasan Tezcan
相关产品推荐
相关产品推荐

