What does ${1+"$@"} mean
...and where is it necessary?
2012-06-16 (see recent changes)
It's a workaround for older releases of the traditional Bourne shell: they parse "$@" in an unexpected way if no arguments were supplied.
All traditional Bourne shells since the SVR3 release and all modern bourne compatible shells behave intuitively.
One might argue, whether the old behaviour is a bug in the very sense, or unintuitive de-facto behaviour. But it was not properly specified, yet, and definitely error-prone.
(It's also a workaround for a problem in various shells if you want to use set -u. See more at the bottom of this page, "Oh wait, ...")
Example
in a shell, where this workaround is necessary.
With the following script,
$ cat args.sh
for i in "$@"; do
echo arg: \"$i\"
done
you get output as expected if you provide at least one argument:
$ sh args.sh 1 2
arg: "1"
arg: "2"
However, without arguments, you still get (empty) output, instead of no output at all:
$ sh args.sh
arg: ""
Why is this relevant?
Keep in mind, that "$@" is most frequently used for passing on arguments, or for iterating over them in a loop, like above.
Thus a mechanism for collapsing the argument list to nothing--and not to the empty argument--is needed.
How does it work?
The ${1+"$@"} syntax first tests if $1 is set, that is, if there is an argument at all.
If so, then this expression is replaced with the whole "$@" argument list.
If not, then it collapses to nothing instead of an empty argument.
Why does it work this way?
The problem only arises if a variable is quoted, and $1 is not.
The workaround is not limited to this variant. These work also: ${@+"$@"} and ${*+"$@"},
but the abovementioned variant is the widely known one.
Another, historic problem
Even with the above workaround, early shells before SVR2 (7th edition, BSDs, SysIII and SVR1) discard empty arguments in the argument list.
$ sh ./args.sh 1 '' 2
arg: "1"
arg: "2"
This looks quite similar at first, but in practice it's less relevant, because dealing without any argument is much more likely to happen.
Portability
${1+"$@"} is reliable and portable -- with one exception:
zsh until release 4.3.0, in sh emulation mode (which means the option shwordsplit is set), does word splitting on the resulting arguments.
$ sh ./args.sh '1 2'
arg: "1"
arg: "2"
An alternative
You might just loop yourself over the arguments:
for i
do
echo "$i"
done
interestingly also valid if merged but without semicolon:
for i do
echo "$i"
done
Although these are not documented for the Version 7 Bourne shell (and its variants on early BSDs), they work on these systems, too.
(Picked up from the german lang usenet posting <3BE2D2D3.I715123W@bigfoot.de> from Gunnar Ritter; and I could confirm this on all the flavours).
See more details about this short form of the for-loop at the end of this page.
In contrast to ${1+"$@"}, these variants even work correctly in the pre-SVR2 variants if there are empty arguments in the list (pointed out by Stéphane Chazelas and I can confirm it).
However, for passing on the arguments to another program (instead of iterating over them) ${1+"$@"} (or "$@") is certainly the only solution.
Which Bourne shells exactly need the workaround?
These shells behave the old way and need ${1+"$@"}:
Certainly: /bin/sh on 7th edition (aka Version 7). And thus also /bin/sh on original BSDs, until these shipped the Almquist shell (after 4.3BSD-Reno)
HP-UX 8, 9 /bin/sh, HP-UX 10.x, 11.x /usr/old/bin/sh (as /bin/sh has become a ksh)
OSF1/V4 and V5 aka Tru64 /bin/sh
Ultrix /bin/sh and /bin/sh5
Sinix 5.20 /bin/sh in both the "ucb" and the "sie" universe
In contrast, these Bourne shell variants behave the modern way:
8th edition (aka Version
/bin/sh
SunOS 4.1.x and SunOS 5.x /bin/sh
IRIX 5 - IRIX 6.3 /bin/sh, IRIX 6.4+x /usr/bin/bsh (as /usr/bin/sh has become a ksh)
AIX 3.2.4 /bin/sh, AIX 4.x /usr/bin/bsh (as /usr/bin/sh has become a ksh)
OpenServer 3 ff. /usr/bin/sh
MUNIX 3.1 (Cadmus, SVR3.1) /bin/sh
Sinix 5.20 /bin/sh in the "xopen" universe
Oh wait, there's another meaning
It's also a workaround for a problem in some shells if you want to use the flag u ("error upon using empty variables")
and "$@" (or $@, "$*", $*) is used without arguments. Example:
$ shell -cu 'echo "$@"; echo not reached'
@: parameter not set
$ shell -cu 'echo ${1+"$@"}; echo ok'
ok
These shells for example need that workaround:
bash-4.0.0 ... -4.0.27
Bourne shells (traditional)
dash-0.4.6 ... -0.4.18
ksh88
ksh93 until release t+20090501
mksh (as pdksh descendant)
NetBSD 2 ff. /bin/sh
pdksh-5.1.3, -5.2.14
posh < 0.10 (as pdksh descendant)
Endnote
Details about the short form of the for-loop.
Among the four variations
$ for i
do
$ for i do
$ for i; do
$ for i;
do
The original 7th ed Bourne shell and all its later flavours don't accept the third and fourth variant [1].
Interestingly, the second variant is accepted (which isn't consistent with accepting the first, but consistent with not accepting the third).
ksh86, ksh88a ff. and ksh93(d..u) accept all but the fourth variant.
The reason might be that the code is partly based on the Bourne shell.
The original Almquist shell (ash) accepts all but the second variant.
It just handles the terminator sort of consistently.
The almquist shells since 4.4BSD and 386BSD (and thus all descendants except Minix pre-3.1.3)
accept all four variants, apparently fixed for backwards portability or flexibility.
All other shells I tried accept all four variants (apparently intentionally being backwards portable or flexible, too),
bash-1.05 ff., pdksh-5.2.14 (thus mksh, posh.), zsh-3.0 ff.
The third variant is not POSIX conformant.
Update: Jens Schweikhardt reported it as issue, and Jilles Tjoelker mentioned the fourth variant, which I added here.
[1] This is weird because ; (semicolon) and newline are usually equivalent.
The documentation doesn't explicitly tell if a terminator is required/allowed; it seems to read as if it's not allowed
for name [in word ...] do list done
Each time a for command is executed name is set to the
next word in the for word list If in word ... is omit-
ted then in "$@" is assumed. Execution ends when there
are no more words in the list.
Comparison with the while control command suggests itself, but is not helpful. The while description doesn't match behaviour, because the terminator in list is not optional
(and because it's incorrect anyway, because "do list" is not optional as written, which will be fixed in the System III documentation),
while list [do list] done
A list is a sequence of one or more pipelines separated by
;, &, && or || and optionally terminated by ; or &. [...]
Newlines may appear in a list, instead of semi-
colons, to delimit commands.
相关推荐
特别地,我们假设在($$ 2 + 1 $$ 2 + 1)维度中没有宇宙学常数的爱因斯坦-功率-麦克斯韦理论,假设重力和电磁耦合均与尺度相关,我们将详细研究尺度如何 依赖的场景会影响任何功率参数值的经典黑洞的视界和热力学...
万能makefile写法详解,一步一步写一个实用的makefile,详解 sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' $@.$$$$ > $@; \-附件资源
$mutations[$i + 1][$j + 1] = $mutations[$i][$j]; } else { // 尝试替换、插入和删除操作 $mutations[$i + 1][$j + 1] = min([ $mutations[$i][$j] + 1, $mutations[$i + 1][$j] + 1, $mutations[$i][$j + ...
通过Ξcc + + $$ {\ Xi} _ {cc} ^ {++} $$搜索Ξcc + + $$ {\ Xi} _ {cc} ^ {++} $$重子 D + pK-π+衰减是通过与LHCb实验在13 TeV质心能量下pp碰撞中通过LHCb实验记录的1.7 fb -1的综合光度对应的数据样本执行的。...
function utf_substr($str,$len){ ... $temp_str=substr($str,0,1); if(ord($temp_str) > 127){ $i++; if($i<$len){ $new_str[]=substr($str,0,3); $str=substr($str,3); } }else{
我们将轴向矢量介子$$ K_1(1270)$$ K1(1270)和$$ K_1(1400)$$ K1(1400)视为两个$$ | ^ 3P_1 \ rangle $$ |3P1⟩和 $$ | ^ 1P_1 \ rangle $$ |1P1⟩的混合角$$ \ theta $$θ等于$$(-34 \ pm 13)^ \ circ $$...
特殊变量列表 变量 含义 $0 当前脚本的文件名 $n 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2。...命令行参数用 $n 表示,例如,$1 表示第一个参
$value = 1; for ($i = 0; $i $rows; $i++) { for ($j = 0; $j $cols; $j++) { $matrix[$i][$j] = $value++; if (($i + $j) % 2 == 1) { if ($j == $cols - 1) { $i++; } else { $j++; } } else { if ($...
^ {-1} $$ fb-1。 得到以下结果:$$ \ begin {aligned} \ mathcal {B}({{B} ^ +} \!\ rightarrow {{J / \ psi}} {{\ rho} ^ +})&=( 3.81 ^ {+ 0.25} _ {-0.24} \ pm 0.35)\ times 10 ^ {-5},\\ \ mathcal {A...
// 1. 对数组进行排序 sort($nums); // 2. 初始化结果集 $result = []; // 3. 双重循环寻找三数之和 for ($i = 0; $i ($nums) - 2; $i++) { // 避免重复元素 if ($i > 0 && $nums[$i] == $nums[$i - 1])...
##### 1. Image$$RO$$Base 与 Image$$RO$$Limit - **Image$$RO$$Base**:指定了只读代码段(ROM code)的起始地址。例如,在示例中提到的 `0x0c100000` 是程序的入口地址,也是只读代码区的起始位置。 - **Image$...
$counter += 1; ``` 在循环结构中,计数器特别有用。例如,`for`循环就是一个常用于计数的场景: ```php for ($i = 0; $i ; $i++) { echo "这是第 " . $i . " 次迭代\n"; } ``` 在这个例子中,`$i`就是计数器,...
$n[$lo + 1] = $n[$hi - 1]; $n[$hi - 1] = $t; $lo++; $hi--; } } $n[$left] = $n[$lo]; $n[$lo] = $pivot; return $lo; } function quicksort(&$n, $left, $right) { global $n; if ($left $right) { ...
输入的第1行是一个整数T,表示测试数据的个数(1)。接下来有T组测试数据。各组测试数据的第1行是一个整数T,表示第i组数据中串的个数。各组测试数据的第2到N+1行,每行一个串,串中不会有空格,但行首和行末可能有...
ARM映像文件中的RO、RW和ZI DATA ARM映像文件是一种可执行文件,包括bin或hex两种格式,可以直接烧到ROM中执行。在ARM集成开发环境中,一个程序包括只读的代码段和可读写的数据段。只读的代码段和常量被称作RO段...
$directions = [ [-1, 0], [1, 0], [0, -1], [0, 1] ]; // 上下左右四个方向 $count = 0; for ($i = 0; $i $m; $i++) { for ($j = 0; $j $n; $j++) { if ($grid[$i][$j] === '1') { $grid[$i][$j] = '0'; // ...
更重要的是,我们预测2P $$ \ Lambda _ {c} ^ + $$Λc+状态的质量反比关系,即$$ \ Lambda _c(2P,1/2 ^-)$$Λc (2P,1 / 2-)状态高于$$ \ Lambda _c(2P,3/2 ^-)$$Λc(2P,3 / 2-),这与常规淬火夸克...
假设我们有两个已排序的数组`array1`和`array2`,目标是将这两个数组合并成一个新的有序数组。这里的“有序”意味着数组中的元素按升序排列。我们需要设计一个算法,能在尽可能短的时间内完成合并,并保持新数组的...
3. 开始外层循环,共进行`$length - 1`轮,因为每次遍历都能确定一个最大(或最小)值。 4. 在每轮中,进行内层循环,从第一个元素开始到倒数第二个元素(`$length - 1`)。 5. 在内层循环中,比较相邻两个元素,...
这两种操作虽然表面上看起来都是将变量的值增加1,但实际上它们的执行顺序和结果存在细微的差别,理解这些差异对编写正确的代码至关重要。 首先,我们来看前置自增运算符(++$i)的用法。当使用++$i时,PHP解释器会...