定界符内“$@”的扩展

定界符内“$@”的扩展

考虑以下脚本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 语法的字符串:

  1. 替换''\''.
  2. 添加'在开头和'结尾。

答案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

相关内容