${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)中仍然存在。
另请参阅: