为什么 $0 不是位置参数?

Ste*_*eve 5 shell bash parameter

我已阅读,位置参数在开始$1(例如:$1$2$3等等是位置参数)。但$0不是位置参数。

但为什么$0不是位置参数?

我认为这可能是一个原因,但不确定:

位置参数仅在执行脚本时采用它们的值。例如:如果我们这样做./myScript Hello,那么$1将有值Hello。但是$0可以在两种情况下取​​其值:执行脚本时(它将具有脚本名称的值),以及在bash没有脚本的情况下执行自身时(它将具有值bashor -bash)。

Sté*_*las 13

@ikkachu比我解释得更好。我只会添加一个历史记录。

Unix 的第一个版本(后来命名为 Thompson shell)附带的 shell 没有变量,但您已经可以编写带参数的简单脚本。

     sh [ name [ arg1 ... [ arg9 ] ] ]

The name is the name of a file which will be read and in?
terpreted.   If  not given, this subinstance of the shell
will continue to read the standard input file.

In command lines in the  file  (not  in  command  input),
character  sequences of the form "$n", where n is a digit
0, ..., 9, are replaced by the nth argument to the  invo?
cation of the shell (argn).  "$0" is replaced by name.
Run Code Online (Sandbox Code Playgroud)

$1...$n已经是$0脚本的参数和名称(不是第一个参数),但当时没有被称为位置参数

请注意,当时,$1在 shell 解释之前,字面上被替换为第一个参数。

例如,一个脚本具有:

echo $1
Run Code Online (Sandbox Code Playgroud)

称为

sh script 'foo; echo bar'
Run Code Online (Sandbox Code Playgroud)

会跑echo foo; echo bar。这个 shell 是一个非常简单的 shell,它是为具有几百 KB 内存的计算机编写的。

大约十年后(70 年代后期),Bourne shell 出现了一个引入环境和其他好处的 Unix 版本。

Bourne shell 确实带有变量和更多的编程结构。

位置参数术语,至少是当它涉及到Unix外壳,由Bourne shell的介绍,并提到了同样的事情,$1......$n的脚本(和参数$0仍脚本的名称)。就像在 Thompson shell 中一样,您只能使用位置参数$1来引用前 9 个参数 ( to $9)(但使用 shift 或"$@"for i doloops 来访问其余部分)(这也解释了(向后可移植性)为什么您需要${10}而不是$10在大多数现代sh第 10 个的实现)。

这一次,sh script 'foo; echo bar'不再引起echo bar来运行,但仍然是Bourne shell介绍,臭名昭著的分裂+水珠,我想不打破向后兼容太多与汤普森外壳,使script 'foo *'其中scriptecho $1还打过电话echofoo和文件的列表当前目录作为参数(就像在 Thompson shell 中一样,但这次通过不同的机制)。

脚本也称为shell 过程(请注意,Bourne shell 还没有函数):

2.0 Shell procedures

The shell may be used to read and execute commands contained
in a file.  For example,

         sh file [ args  ]

calls the shell to read commands from file.  Such a file  is
called  a  command  procedure or shell procedure.  Arguments
may be supplied with the call and are referred  to  in  file
using  the  positional parameters $1, $2...
Run Code Online (Sandbox Code Playgroud)

函数于 80 年代初首次在 Korn shell(基于 Bourne shell)中引入

function foo {
  ...
}
Run Code Online (Sandbox Code Playgroud)

句法。

函数最终也被添加到 Bourne shell 中,后来在 SysVR2 (1984) 中使用了不同的语法:

foo() any-command
Run Code Online (Sandbox Code Playgroud)

(但是当any-command是一个简单的命令并且有重定向时,会有意外的行为,这可能是 POSIX 只需要复合命令(如{ ...; }最常用的命令)在 POSIX 中被识别的原因sh)。

在 Korn 和 Bourne shell$0中,函数中仍然是脚本名称,而不是函数名称(而$1,$2位置参数指的是函数参数)。

更改ksh93function f {函数定义的样式,其中$0成为函数中的函数名称。

zsh,$0是 ksh93 中的函数名称。zsh还引入了具有以下任一功能的匿名函数:

function { echo $1, $2; } foo bar
Run Code Online (Sandbox Code Playgroud)

或者

(){ echo $1, $2; } foo bar
Run Code Online (Sandbox Code Playgroud)

语法,其中$0变为(anon)(或set +o functionargzerosh/ksh仿真中使用like保留脚本的名称)。

在 中zsh,与 in 一样csh,脚本的参数也在$argv数组中,这消除了与参数名称相似的程序名称的混淆。

在那里,您可以使用以下命令为位置参数赋值:

argv[1]=value
Run Code Online (Sandbox Code Playgroud)

或者

1=value
Run Code Online (Sandbox Code Playgroud)

(以及0=newprogramname更改程序名称)。

而在其他类似 Bourne 的 shell 中,您需要set一次使用来分配:

set -- arg1 arg2
Run Code Online (Sandbox Code Playgroud)

而你无法改变$0

rc(至少是 Unix 端口)中,您不能这样做:

1 = value
Run Code Online (Sandbox Code Playgroud)

但你可以这样做:

* = (arg1 arg2)
Run Code Online (Sandbox Code Playgroud)

设置位置参数。你不能改变$0in rc,但你可以在它的衍生物中es使用0=newprogramname类似 in zsh

TL; 博士

$1$2...来引用脚本参数来自汤普森外壳,但还不能称作位置参数呢。并且$0(可能参考argv[0]@ikkachu 说得好)指的是脚本名称。

位置参数术语来自Bourne shell的。

$0不是位置参数,因为它不引用脚本的参数。它指的是脚本的名称(或argv[0]当外壳不执行任何脚本时外壳的名称)。


ilk*_*chu 9

从编号参数 ( $0, $1, ...) 到argv[]包含进程启动时命令行参数的数组之间存在明显的平行关系。数组的第一个元素argv[0],通常保存进程的名称,实际参数从 开始argv[1]

(通常。它不必。状态描述execve(2):“中的值argv[0] 指向与正在启动的进程关联的文件名字符串”)

至少事后,很容易想象这个约定只是直接复制到 shell 中。

但是,这些值不会直接复制。至少在我的系统上./script.sh,使用 hashbang运行时启动的 shell 进程 #!/bin/bash -x获取参数/bin/bash, -x, ./script.sh。也就是说,$0脚本看到的值argv[2]在 shell 进程中。

我假设大多数人会认为命令名称与其参数不同,因此$0功能上与其他名称不同,因此以不同方式称呼它也并非不合理。

当然,我们可以使用具有不同命名约定的脚本语言。Perl 将程序名称放在一个名为 的变量中$0,并将参数放在数组中@ARGV,从索引零开始,即$ARGV[0]等。


无论如何,最明显的答案是说这$0不是位置参数,因为标准是这样说的

2.5 参数和变量

2.5.1 位置参数

位置参数是用一位或多位数字表示的十进制值表示的参数,而不是单个数字 0。

2.5.2 特殊参数

# 扩展到位置参数的十进制数。命令名称(参数 0)不应计入由 ' #'给出的数字,因为它是一个特殊参数,而不是位置参数。

0 (零。)扩展到 shell 或 shell 脚本的名称。


Mar*_*elo 4

$0 实际上是一个位置参数(正如下面 Michael Homer 注释中所指出的那样,POSIX 说“...将参数名称作为编号为 1 到 n 的位置参数,以及命令的名称(或者在函数的情况下)在脚本中,脚本的名称)作为编号为 0 的位置参数”。

正如人们所预料的那样,它是位置 0 的参数,代表调用命令的名称。

这非常有用,因为它允许相同的脚本根据其调用名称而有不同的行为,从而允许相同的可执行文件具有多个函数(例如,考虑符号链接)。这允许进程知道它的调用名称是什么。

如果你快速浏览一下 /bin,你会看到很多这样的例子,比如 bzcat、bzcmp、bzip2,...;mdir、mcat、mcd、mdel、...;xz、xzcat、unxz 等等。进程知道要执行什么功能的方式是通过检查位置参数 0。

注意:某些 shell 手册页可能以不同的方式处理术语:bash 的手册页说它不是位置参数,ksh 的手册页(和 POSIX 定义)说它是。无论任何术语讨论如何,在(bash 和 ksh)中,$0 都包含调用命令或脚本的名称。如果这是一个交互式 shell,$0 将包含 shell 的名称(bash、ksh...),因为它是进程名称。

  • [POSIX 说“...将参数的名称作为编号为 1 到 n 的位置参数,并将命令的名称(或者在脚本内的函数的情况下,脚本的名称)**作为位置参数参数编号为 0**"](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_02) (2认同)
  • 另一方面: `$#` "扩展为位置参数的十进制数。命令名称(参数 0)不应计入 '#' 给出的数字中,因为它是特殊参数,而不是位置参数。 ” [2.5.2 特殊参数](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_05_02) (2认同)