在 Perl 文档中,perlrun(1)建议使用双语 shell/Perl 头文件启动 Perl 脚本:
#!/bin/sh
#! -*-perl-*-
eval 'exec perl -x -wS $0 ${1+"$@"}'
if 0;
Run Code Online (Sandbox Code Playgroud)
什么${1+"$@"}意思?我尝试"$@"改用(使用 Bash 作为 /bin/sh),它似乎也能正常工作。
下面的两个答案说它应该是${1:+"$@"}. 我知道${parameter:+word}bash(1) 中记录的(“使用替代值”)语法。然而,我不相信,因为
无论${1+"$@"}和"$@"工作得很好,即使在没有参数。如果我创建 simple.sh 作为
#!/bin/sh
eval 'exec /usr/bin/perl -x -S -- $0 "$@"'
if 0;
#!perl
use Data::Dumper;
print Dumper(\@ARGV);
Run Code Online (Sandbox Code Playgroud)
和 question.sh 作为
#!/bin/sh
eval 'exec /usr/bin/perl -x -S -- $0 ${1+"$@"}'
if 0;
#!perl
use Data::Dumper;
print Dumper(\@ARGV);
Run Code Online (Sandbox Code Playgroud)
我可以让两者以相同的方式工作:
$ ./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 = [
''
];
Run Code Online (Sandbox Code Playgroud)也许${parameter+word}是未记录的替代(或弃用)语法${parameter:+word}? 有人能证实这个假设吗?
Sté*_*las 57
这是为了与 Bourne shell 兼容。Bourne shell 是一个旧的 shell,它于 1979 年首次随 Unix 版本 7 一起发布,直到 90 年代中期仍然像/bin/sh大多数商业 Unices一样常见。
它是大多数类似 Bourne 的 shell的祖先,例如ksh,bash或zsh。
它有一些笨拙的功能,其中许多功能已在ksh其他 shell 和 的新标准规范中得到修复sh,其中之一是:
使用 Bourne shell(至少那些尚未修复的变体):"$@"如果位置参数列表为空 ( $# == 0) 而不是根本没有参数,则扩展为一个空参数。
${var+something}除非$var未设置,否则扩展为“某物” 。它在所有 shell 中都有清楚的记录,但在文档中很难找到,bash因为您需要注意这句话:
当不执行子字符串扩展时,使用下面记录的形式,bash 测试未设置或为空的参数。 省略冒号会导致仅对未设置的参数进行测试。
因此${1+"$@"}扩展为"$@"仅当$1设置为 ( $# > 0) 时,它可以解决 Bourne shell 的限制。
请注意,Bourne shell 是唯一存在该问题的 shell。Modern shs(sh符合 POSIX 规范sh(Bourne shell 不符合))没有这个问题。因此,如果您需要您的代码在/bin/sh可能是 Bourne shell 而不是标准 shell 的非常旧的系统上工作,您只需要这样做(请注意,POSIX 没有指定标准的位置,sh例如在 Solaris 11 之前的 Solaris 上,/bin/sh仍然是 Bourne shell(虽然没有那个特殊问题),而正常/标准sh在另一个位置(/usr/xpg4/bin/sh))。
但是,该perlrunperldoc 页面中存在一个问题,$0但未引用该页面。
有关更多信息,请参阅http://www.in-ulm.de/~mascheck/various/bourne_args/。
两者之间存在差异:
command ""
Run Code Online (Sandbox Code Playgroud)
和
command
Run Code Online (Sandbox Code Playgroud)
在其中一种情况下,您传递的参数是一个空字符串。在第二个中,传递了零个参数。
对于两者来说,“$@”将等同于同一件事:""。但使用${1:+"$@"}将用于""第一个,并且不会为第二个传递任何参数,这就是意图。
如果您正在执行下面的脚本(称为 sshwrapper),您可以使用可选命令或不带参数来调用该脚本来获取交互式 shell,那么这一点就变得很重要。
: sshwrapper [command]
exec /usr/bin/ssh "${HOSTNAME:-localhost}" "$@"
Run Code Online (Sandbox Code Playgroud)
这将尝试在远程主机上运行“”(仅返回),它不是交互式 shell。
: sshwrapper [command]
exec /usr/bin/ssh "${HOSTNAME:-localhost}" ${1:+"$@"}
Run Code Online (Sandbox Code Playgroud)
将在远程主机上启动交互式 shell,因为 exec 会正确地将变量解释为空,而不是空字符串。
阅读 bash 手册页中的“${parameter:+word}”(“使用替代值”)和类似变量扩展字符串的用法。