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