Bash 何时使用 $@、"$@" 和 ${1+"$@"}

Bash 何时使用 $@、"$@" 和 ${1+"$@"}

${1+"$@"}tl;dr ...找到一个用于将命令行参数转发到另一个脚本的脚本。这到底是做什么的?什么时候用它代替$@and "$@"

有一个名为 的简单 shell 脚本runhaskell,在 Ubuntu 15.10(或许还有其他版本)上随 ghc 一起分发。我正在尝试找出如何用能够识别阴谋集团沙箱的东西来替换它。 shell 脚本看起来像这样。它似乎有一些未使用的变量和不必要的类似 shebang 的注释(来自脚本的早期版本?)

#!/bin/bash
exedir="/usr/lib/ghc/bin"
exeprog="runghc"
executablename="$exedir/$exeprog"
datadir="/usr/share"
bindir="/usr/bin"
topdir="/usr/lib/ghc"
#!/bin/sh

exec "$executablename" -f "$bindir/ghc" ${1+"$@"}

我无法理解最后一行。/usr/lib/ghc/bin/runghc是一个runhaskell显然委托给的本机可执行文件,它传入的参数之一是编译器的位置。好的没问题。

它有什么${1+"$@"}作用以及什么时候应该使用它?我最好的猜测是,这1只是一个总是成功的测试,并且这种构造只是用于逐字传递参数。我记得 POSIX 要求这样做$@,并且"$@"其行为与您的期望有所不同,但我不记得确切的细节。

答案1

${var+foo}foo如果设置了变量var(即使为空),则扩展为其他内容。在本例中,变量是第一个位置参数$1。因此,${1+"$@"}检查是否$1已设置并相应地扩展"$@",除此之外什么也没有。

至于$@"$@",$@在扩展到位置参数后会受到字段分割和文件名扩展的影响,而"$@"不是:

$ sh -c 'cd /usr; printf "%s\n" $@' _ 'a b' '*'  
a
b
bin
include
$ sh -c 'cd /usr; printf "%s\n" "$@"' _ 'a b' '*'
a b
*

你几乎总是想使用"$@"over $@

至于${1+"$@"}vs just "$@",在 POSIX 兼容的 shell 中,两者具有相同的效果。根据这个堆栈溢出帖子:

“歇斯底里的葡萄干”,又名历史原因。

大约 20 年前,Bourne Shell 的一些损坏的小变体在没有参数的情况下用空字符串替换,而不是当前正确的不替换任何内容的行为"""$@"此类系统是否仍在使用尚有争议。

autoconf 手册部分壳牌替代品也涉及到这个:

特定扩展还存在可移植性陷阱:

$@

最著名的 shell 可移植性问题之一与“ "$@"”有关。当没有位置参数时,Posix 表示 ' "$@"' 应该等于什么都没有,但原始 Unix 版本 7 Bourne shell 将其视为等效于 ' ""',这种行为在以后的实现(如 Digital Unix 5.0)中仍然存在。


另请参阅:

相关内容