Ste*_*ein 6 shell bash quoting
我正在将嵌入式平台上的 bash 从 4.1.9 更新到最新版本 (4.4.12),并且我看到在将转义参数传递到脚本的这个简单场景中的行为发生了变化。
脚本/tmp/printarg:
#! /bin/sh
echo "ARG |$*|"
Run Code Online (Sandbox Code Playgroud)
我像这样调用脚本:
bash -c "/tmp/printarg \\"abc\\""
Run Code Online (Sandbox Code Playgroud)
我已经在运行 bash 4.3.42 的几个平台(原生 x86_64 Linux)以及运行 bash 4.1.9 和 4.2.37 的几个嵌入式平台(ARM 和 PPC)上尝试了这个,所有这些平台都报告了我的期望:
38$ bash -c "/tmp/printarg \\"abc\\""
ARG |abc|
Run Code Online (Sandbox Code Playgroud)
但是,当我使用 bash 4.4.12(原生 X86 或嵌入式平台)运行它时,我得到了这个:
$ bash -c "/tmp/printarg \\"abc\\""
ARG |abc\| <<< trailing backslash
Run Code Online (Sandbox Code Playgroud)
如果我在命令行中的第二个转义引号和结束引号之间添加一个空格,那么我将不再看到额外的反斜杠:
$ bash -c "/tmp/printarg \\"abc\\" "
ARG |abc | <<< trailing space, but backslash is gone
Run Code Online (Sandbox Code Playgroud)
这感觉像是一种回归。有什么想法吗?我也尝试通过更改启用各种兼容选项(compat40、compat41、compat42、compat43)。
bash -c "/tmp/printargs \\"abc\\""
Run Code Online (Sandbox Code Playgroud)
不会逃避你认为它会做什么。反斜杠-反斜杠是一个转义的反斜杠,由调用 shell 处理——所以这与运行相同:
/tmp/printargs \abc\
Run Code Online (Sandbox Code Playgroud)
因为双引号没有被转义。你可以只写:
bash -c '/tmp/printargs \abc\'
Run Code Online (Sandbox Code Playgroud)
我猜你真的想要:
bash -c "/tmp/printargs \"abc\""
Run Code Online (Sandbox Code Playgroud)
它转义双引号,将带引号的“abc”传递给 bash -c。
(我猜你看到的不同行为是不同版本的 bash 以不同的方式处理输入结束时转义的内容。)
打印参数的 Perl 版本(稍微改进了行为):
bash -c "/tmp/printargs \\"abc\\""
Run Code Online (Sandbox Code Playgroud)
bash -c "/tmp/printargs \\"abc\\""
Run Code Online (Sandbox Code Playgroud)
你确定这是你想要做的吗?如果你运行它set -x,你会看到运行的命令是
bash -c '/tmp/printargs \abc\'
Run Code Online (Sandbox Code Playgroud)
即,您正在向 shell 传递一个以反斜杠结尾的字符串。您的第一个带引号的字符串包含一个转义的反斜杠,然后您有一个 unquoted abc、一个转义的反斜杠,然后是一个空的带引号的字符串。(请注意 Stackexchange 完成的语法突出显示如何显示abc未引用。)
输入末尾的未加引号的反斜杠没有多大意义。反斜杠要么转义以下字符,要么开始一个续行,在那里它与以下换行符一起被删除,如下所示:
$ bash -c $'echo "foo\\\nbar"'
foobar
Run Code Online (Sandbox Code Playgroud)
本案两者都没有。您可能正在尝试执行以下任一操作:
bash -c "/tmp/printargs \"abc\""
bash -c '/tmp/printargs "abc"'
Run Code Online (Sandbox Code Playgroud)
两者都产生输出ARG |abc|。
我们可以通过更简单的测试看到 shell 之间的区别:
bash -c "/tmp/printargs \\"abc\\""
Run Code Online (Sandbox Code Playgroud)
如果我不得不猜测,我会开始寻找这个变化的变化来源:
bash -c '/tmp/printargs \abc\'
Run Code Online (Sandbox Code Playgroud)