考虑以下脚本1:
#!/bin/bash
bash <<END
printf "%s\n" "$@"
END
Run Code Online (Sandbox Code Playgroud)
令人惊讶的是(对我来说),$@
这里文档的内部首先被扩展,然后被引用,所以这是输出:
$ /tmp/test.sh "a a" b c
a a b c
Run Code Online (Sandbox Code Playgroud)
如果我删除引号,我会得到简单的$@
行为:
$ /tmp/test.sh "a a" b c
a
a
b
c
Run Code Online (Sandbox Code Playgroud)
这两个选项都无法提供所需的输出。我尝试使用类似 的数组args=("$@")
,但扩展的行为方式相同。我尝试将“结果”放入诸如 之类的变量中args="$@"
,但这只会返回“aab c”。
有什么想法如何使输出如下所示?
a a
b
c
Run Code Online (Sandbox Code Playgroud)
1显然,这是非常简单的。实际上,我正在使用heredoc来执行脚本docker run
,但这对这个问题来说并不重要。
在此处的文档中,shell 执行 \xe2\x80\x9cdollar 替换 \xe2\x80\x9d ($foo
使用$(some command)
、 、`some command`
、$((x+1))
和反斜杠进行保护\\`$
)。这里的文档像双引号字符串一样展开。为了避免这种情况,请在此处文档的结束标记上使用引号,然后该文档的行为就像单引号字符串(根本不扩展)。
bash <<\'END\'\nprintf "%s\\n" "$@"\nEND\n
Run Code Online (Sandbox Code Playgroud)\n这不会做你想要的事情,因为它"$@"
是由内部 bash 扩展的,并且它不接收任何参数。最简单的直接解决方案(在您的实际用例中可能有效也可能无效)是将参数转发到内部 bash。
bash /dev/stdin "$@" <<\'END\'\nprintf "%s\\n" "$@"\nEND\n
Run Code Online (Sandbox Code Playgroud)\n如果您无法在实际用例中将参数传递给内部 bash,则可以通过环境变量传递它们。但是每个环境变量只能传递一个字符串,因此如果要传递的字符串数量可变,则这并不方便。
\nexport widget_count="$1" data_source="$2" frobnicator="$3"\n\xe2\x80\xa6\nbash <<\'END\'\nprintf "%s\\n" "$widget_count" "$data_source" "$frobnicator"\nEND\n
Run Code Online (Sandbox Code Playgroud)\n作为最后的手段,您可能需要引用这些值来传递它们。要引用 shell 语法的字符串:
\n\'
为\'\\\'\'
.\'
在开头和\'
结尾。