$ {1 +“ $ @”}在shell脚本中是什么意思,它与“ $ @”有什么区别?


43

在Perl文档中,perlrun(1)建议使用双语shell / Perl标头启动Perl脚本:

#!/bin/sh
#! -*-perl-*-
eval 'exec perl -x -wS $0 ${1+"$@"}'
    if 0;

什么${1+"$@"}意思 我尝试使用"$@"代替(使用Bash作为/ bin / sh),它似乎同样有效。


编辑

以下两个答案说应该是${1:+"$@"}。我知道${parameter:+word}bash(1)中记录了(“使用替代值”)语法。但是,我不敢相信,因为

  1. 无论${1+"$@"}"$@"工作得很好,即使在没有参数。如果我创建simple.sh为

    #!/bin/sh
    eval 'exec /usr/bin/perl -x -S -- $0 "$@"'
        if 0;
    #!perl
    use Data::Dumper;
    print Dumper(\@ARGV);

    和question.sh为

    #!/bin/sh
    eval 'exec /usr/bin/perl -x -S -- $0 ${1+"$@"}'
        if 0;
    #!perl
    use Data::Dumper;
    print Dumper(\@ARGV);

    我可以使两者相同地工作:

    $ ./question.sh 
    $VAR1 = [];
    $ ./question.sh a
    $VAR1 = [
              'a'
            ];
    $ ./question.sh a 'b c'
    $VAR1 = [
              'a',
              'b c'
            ];
    $ ./question.sh ""
    $VAR1 = [
              ''
            ];
    $ ./simple.sh 
    $VAR1 = [];
    $ ./simple.sh a
    $VAR1 = [
              'a'
            ];
    $ ./simple.sh a 'b c'
    $VAR1 = [
              'a',
              'b c'
            ];
    $ ./simple.sh ""
    $VAR1 = [
              ''
            ];
  2. Internet上的其他来源也可以使用${1+"$@"},包括一名黑客似乎知道他在做什么。

也许${parameter+word}是未记录的替代(或不推荐使用)语法${parameter:+word}?有人可以确认这个假设吗?


Answers:


53

这是为了与Bourne Shell兼容。Bourne外壳是一个旧的外壳,该外壳在1979年与Unix版本7一起首次发布,直到90年代中期,/bin/sh在大多数商业Unices上仍然很常见。

这是大多数祖先类似Bourne壳kshbashzsh

它具有一些尴尬的功能,其中许多功能已修复,ksh其他的外壳以及的新标准规范sh,其中之一是:

对于Bourne shell(至少是那些尚未修复的变体):"$@"如果位置参数列表为空($# == 0)而不是完全没有参数,则扩展为一个空参数。

${var+something}除非$var未设置,否则扩展为“某物” 。它清楚地记录在所有shell中,但是在文档中很难找到,bash因为您需要注意以下句子:

当不执行子字符串扩展时,使用下面记录的形式,bash将测试未设置或为null的参数。 省略冒号只会对未设置的参数进行测试

因此${1+"$@"}"$@"只有在$1set($# > 0)可以解决Bourne shell的限制的情况下,才扩展为。

请注意,Bourne外壳是唯一出现此问题的外壳。Modern shs(sh符合POSIX规范sh(Bourne shell不符合))不存在该问题。因此,仅当您需要代码在/bin/sh可能是Bourne Shell而不是标准Shell的非常旧的系统上工作时才需要(请注意POSIX未指定标准位置,sh例如在Solaris 11之前的Solaris上)/bin/sh仍然是Bourne外壳(尽管没有特定问题),而正常/标准sh位于另一个位置(/usr/xpg4/bin/sh)。

perlrunperldoc页面中有一个问题,$0但没有引用。

有关更多信息,请参见http://www.in-ulm.de/~mascheck/various/bourne_args/


无法在传家宝中复制。可能不适用于Solaris。
ormaaj 2013年

2
@ormaaj。是的,请参阅我链接的页面。它已在SVR3中修复,而Solaris / SunOS 5或更高版本基于SVR4进行了修复。该页面提到4.1.x也没有问题。
斯特凡Chazelas

啊,我明白了。<3 Mascheck页面。
ormaaj 2013年

3

之间有一个区别:

command ""

command

在一处,您传递的是一个空字符串的参数。在第二个中,传递了零个参数。

对于这两者,“ $ @”将等同于同一件事:""。但是使用${1:+"$@"}""第一个使用,而第二个没有传递任何参数,这是目的。

如果您正在执行以下名为sshwrapper的脚本,则该脚本非常重要,您可以使用可选命令或不使用任何参数调用该脚本来获取交互式shell。

: sshwrapper [command]
exec /usr/bin/ssh "${HOSTNAME:-localhost}" "$@"

这将尝试在远程主机(仅返回)上运行“”,而不是交互式外壳。

: sshwrapper [command]
exec /usr/bin/ssh "${HOSTNAME:-localhost}" ${1:+"$@"}

将在远程主机上启动交互式Shell,因为exec将正确地将变量解释为空,而不是空字符串。

在bash手册页上阅读“ $ {parameter:+ word}”(“ Use Alternate Value”)和类似的变量扩展字符串的用法。


这似乎仅适用于Bourne shell,不适用于任何符合POSIX的sh实现(请参见其他答案)。
törzsmókus

4
不,${1:+"$@"}如果$1为空,则将扩展为无自变量。你要${1+"$@"}。基本上,你已经扭转了。
斯特凡Chazelas

0

我总结了斯特凡·查泽拉斯的回答:

  • $ {1:+“ $ @”}'测试$ 1是否为空或未设置
  • $ 1未设置$ {1 +“ $ @”}'测试

因此,如果将第二个参数与参数“”一起使用,则意味着$ 1为空,但它不会测试它是否为空,只是看到它已经被设置了,但是它是否为空,因此它将展开$ @ ,但您将$ {1:+“ $ @”}'与“”一起使用,它将不再扩展$@


7
尽管可能无法澄清,但可以肯定地总结一下……
Archemar
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.