通常,$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
称为 assh
或vim
称为 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 的系统),您不知道第一个参数是否进入$0
or $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
,并且同样常见的是该参数与您正在运行的可执行文件相同。但有时,您想要在那里有一个特殊的值,而没有其他方法可以得到它。鉴于参数存在,它必须映射到某些东西,并且用户需要能够设置它是什么。
这种一致性(以及可能的历史事故)导致了您发现的情况。