带有位置参数的 Bash -c

带有位置参数的 Bash -c

通常,$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用于定义程序的行为(labash称为 asshvim称为 as vi),但这不可能,因为$0这里只能在命令字符串中看到,而不能被在命令字符串中调用的程序看到。我想不出 的任何其他用途$0,所以我无法解释这一点。

答案1

这让您有机会设置/选择$0何时使用内联脚本。否则,$0就只是bash

然后你可以这样做:

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

并非所有 shell 都这样做。 Bourne shell 做到了。 Korn(和 Almquist)shell 选择使用第一个参数$1。 POSIX 最终采用了 Bourne 方式,因此ksh衍生ash品后来又恢复了这种方式(更多信息请参见http://www.in-ulm.de/~mascheck/various/find/#shell)。这意味着在很长一段时间内sh(取决于基于 Bourne、Almquist 或 Korn shell 的系统),您不知道第一个参数是否进入$0or $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

答案2

这种行为是由 POSIX 定义:

sh -c 命令名 [参数...]

从 command_string 操作数读取命令。设置特殊参数0的值(参见特殊参数)从 command_name 操作数的值和位置参数($1、$2 等)按顺序从剩余的参数操作数开始。

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

它也符合程序参数的一般工作方式:这最终归结为调用其中之一exec函数,其中第一个提供的参数也是$0,并且同样常见的是该参数与您正在运行的可执行文件相同。但有时,您想要在那里有一个特殊的值,而没有其他方法可以得到它。鉴于参数存在,它必须映射到某些东西,并且用户需要能够设置它是什么。

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

相关内容