具有位置参数的Bash -c


15

通常,$0在脚本中将其设置为脚本的名称,或设置为脚本的名称(包括路径)。但是,如果我使用bash-c选项,$0则设置为命令字符串后传递的第一个参数:

bash -c 'echo $0 ' foo bar 
# foo 

实际上,位置参数似乎已移动,但包含$0。但是shift在命令字符串中不受影响$0(正常情况下):

bash -c 'echo $0; shift; echo $0 ' foo bar
# foo
# foo

为什么对于命令字符串来说这看起来很奇怪?请注意,我在寻找实现这种奇怪行为的原因和理由。


可以推测这样的命令字符串将不需要$0通常定义的参数,因此出于经济考虑,它也用于常规参数。但是,在那种情况下,的行为shift是奇怪的。另一种可能性是$0用于定义程序的行为(bash称为shvim称为la vi),但不能如此,因为$0这里仅在命令字符串中可见,而在命令字符串中不可见。我无法想到的其他用途$0,因此我无所适从。


附带说明一下,我已经将-for $0参数用作习语,例如中的sh -c 'foo $1 $2' - a b。这样看起来就很正常了(一旦您知道那-是什么意思)
Volker Siegel 2014年

echo 'echo the other side of this pipe globs "$@"' | sh -s -- *不幸的$0是,您也-s可以使用tream选项将其设置为不可设置的参数xargs。还有其他。
mikeserv

@VolkerSiegel更正常的做法是--,这可能具有通常的解释“从这里开始论点”,在其他程序中也可以看到。再说一遍,这可能会使那些不熟悉的人误-c以为--实际上确实有这种解释。
muru 2014年

Answers:


10

这使您有机会$0在使用内联脚本时进行设置/选择。否则,$0将是bash

然后,您可以执行以下操作:

$ bash -c 'wc -c < "${1?}"' getlength foo
4
$ bash -c 'wc -c < "${1?}"' getlength bar
getlength: bar: No such file or directory
$ bash -c 'wc -c < "${1?}"' getlength
getlength: 1: parameter null or not set

并非所有的shell都曾经这样做。伯恩(Bourne)壳弹了。Korn(和Almquist)外壳程序选择将第一个参数转到$1。POSIX最终去了伯恩的方式,所以kshash衍生物(在更上恢复到后来http://www.in-ulm.de/~mascheck/various/find/#shell)。这意味着很长一段时间sh(取决于系统是基于Bourne,Almquist还是Korn Shell),您不知道第一个参数是否进入$0$1,因此对于可移植性,您必须执行以下操作:

sh -c 'echo foo in "$1"' foo foo

要么:

sh -c 'shift "$2"; echo txt files are "$@"' tentative-arg0 3 2 *.txt

幸运的是,POSIX已经在第一个参数进入的地方指定了新的行为$0,因此我们现在可以方便地执行以下操作:

sh -c 'echo txt files are "$@"' meaningful-arg0-for-error *.txt

我刚运行:bash -c 'echo txt files are "$@"' meaningful-arg0-for-error *.txt在Ubuntu 14.04,bash上version 4.3.11(1)-release,我得到了:txt files are *.txt。Oo
Muru

2
@muru,这是正确的(并且您可能txt在当前目录中没有文件)。又见bash -c 'echo "${1?}"' foo
斯特凡Chazelas

是啊。这是一个实际有用的例子。
muru

1
sh -c 'shift "$2"; echo txt files are "$@"' tentative-arg0 3 2 *.txt极富创造力!
iruvar

或者您使用完全健壮的解决方法(由StéphaneChazelas建议在comp.unix.shell中建议) SHELL -c 'shift $1; command' 2 1 arg1 arg2 ... 哈哈...
mikeserv

3

此行为由POSIX定义

sh -c command_name [参数...]

从command_string操作数读取命令。从command_name操作数的值设置位置特殊参数0的值(请参见Special Parameters),从其余参数操作数开始依次设置位置参数($ 1,$ 2等)。

至于为什么要这种行为:这可以消除脚本和-c字符串之间的差距。您可以直接在两者之间进行转换,而无需任何更改。其他领域依靠这些相同。

这也与程序参数的总体工作方式一致:这最终归结为调用其中一个exec函数,其中第一个提供的参数也是$0,并且同样通常该参数与您正在运行的可执行文件相同。但是有时候,您希望在那里有一个特殊的值,而没有其他方法可以得到它。给定参数存在,它必须映射到某物,并且用户需要能够设置它。

这种一致性(以及可能的历史事故)会导致您发现这种情况。


您能否举一个第二段的例子(希望是真实世界)?
muru 2014年

细心地与argv[0]$0仅在argv[0]传递给或execve()时设置为。对于脚本,设置为作为解释器的参数1、2 ...给出的路径(对于直接执行的脚本,它来自execve()的第一个路径参数)。shbash$0
斯特凡Chazelas
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.