web-dev-qa-db-ja.com

なぜ$ 0は定位置パラメーターではないのですか?

位置パラメータは$1で始まることを読みました(たとえば、$1$2$3などは位置パラメータです)。ただし、$0は定位置パラメーターではありません。

しかし、$0が位置パラメータではないのはなぜですか?

これは理由かもしれないと思いますが、確かではありません:

定位置パラメーターは、スクリプトが実行されたときにのみ値を取得します。たとえば、./myScript Helloを実行すると、$1の値はHelloになります。ただし、$0は、スクリプトが実行されるとき(スクリプト名の値を持つ)と、スクリプトなしでbash自体が実行されるとき(それは値bashまたは-bash)。

5
Steve

@ ikkachuが説明しました 私ができるよりも優れています。履歴メモを追加します。

Unixの最初のバージョンに付属していたシェル(後にThompson 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.
_

_$1_..._$n_はすでに引数であり、_$0_スクリプトの名前(1番目の引数ではない)ですが、呼び出されませんでした位置パラメーター次に。

その当時、_$1_はシェルによる解釈の前に文字通り最初の引数に置き換えられていたことに注意してください。

たとえば、次のスクリプト。

_echo $1
_

と呼ばれる

_sh script 'foo; echo bar'
_

_echo foo; echo bar_を実行します。そのシェルは、数百キロバイトのメモリを搭載したコンピュータ用に書かれた非常にシンプルなものでした。

Bourne Shellは、約10年後(70年代後半)に、環境とその他の優れた機能を導入したバージョンのUnixを発表しました。

Bourne Shellには、変数とさらに多くのプログラミング構造が付属しています。

位置パラメータの用語は、少なくともUnixシェルに関しては、Bourne Shellによって導入され、同じことを__(SOMECODE)と呼んでいます__... _$1_スクリプトの引数(および_$n_は引き続きスクリプト名)。 Thompson Shellと同様に、最初の9つの引数(_$0_から_$1_)までは、位置パラメーターでのみ参照できます(ただし、シフトまたは_$9_または_"$@"_ループを使用してアクセスします)残りの部分)(そして、(後方移植性)10番目の最新のsh実装で_for i do_ではなく_${10}_が必要な理由も説明されています)。

今回、_$10_によって_sh script 'foo; echo bar'_が実行されることはなくなりましたが、ボーンシェルが悪名高いsplit + globを導入したため、Thompsonシェルとの下位互換性をあまり損なわないため、_echo bar_ scriptが_script 'foo *'_を持っている場合でも、echofooと現在のディレクトリ内のファイルのリストを引数として呼び出します(Thompson Shellのように、これは別のメカニズムによる時間)。

scriptsも呼び出されましたシェルプロシージャ(ボーンシェルはまだ機能があります):

_echo $1_

関数は、80年代初頭にKornシェル(Bourneシェルに基づく)で最初に導入されました。

_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...
_

構文。

関数は最終的にBourne Shellに追加され、SysVR2(1984)の後半に別の構文で追加されました。

_function foo {
  ...
}
_

(ただし、_foo() any-command _が単純なコマンドでリダイレクトがあったときに予期しない動作が発生したため、POSIXで複合コマンド(_any-command_のような最も頻繁に使用されるコマンド)のみが必要となるリダイレクトがPOSIX sh)。

KornシェルとBourneシェルの両方で、関数内の_{ ...; }_は関数名ではなくスクリプト名でした(一方、_$0_、_$1_定位置パラメーターは関数の引数を参照しています)。

_$2_関数の_ksh93_スタイル定義の_function f {_で変更されました。ここで、_$0_は関数内の関数名になります。

zshでは、_$0_はksh93のような関数名です。 zshはまた、次のいずれかを持つ無名関数を導入しました。

_function { echo $1, $2; } foo bar
_

または

_(){ echo $1, $2; } foo bar
_

構文では、_$0_は_(anon)_になります(または、sh/kshエミュレーションの場合と同様に、_set +o functionargzero_でスクリプト名を保持します)。

zshでは、cshと同様に、スクリプトの引数も_$argv_配列にあります。これにより、引数と同様に名前が付けられたプログラム名に関する混乱が解消されます。

そこで、位置パラメータに値を割り当てることができます:

_argv[1]=value
_

または

_1=value
_

(また、プログラム名を変更する場合は_0=newprogramname_)。

他のBourneのようなシェルでは、setを使用して一度にすべてを割り当てる必要があります。

_set -- arg1 arg2
_

また、_$0_は変更できません。

rc(少なくともUnixポート)では、次のことはできません。

_1 = value
_

しかし、あなたはできる:

_* = (arg1 arg2)
_

位置パラメータを設定します。 rcの_$0_は変更できませんが、esのように_0=newprogramname_を使用してその派生物zshを変更できます。

TL; DR

スクリプト引数を参照する_$1_、_$2_...はThompsonシェルからのものですが、呼び出されませんでした位置パラメーターまだ。また、_$0_(@argv[0]_を参照して選択された可能性が高いため、@ ikkachuが適切に記述しています)は、スクリプト名を参照します。

位置パラメータという用語はボーンシェルから来ています。

_$0_は、スクリプトの引数を参照しないため、位置パラメータではありません。スクリプトの名前(またはシェルがスクリプトを実行しない場合はシェルの_argv[0]_)を参照します。

13

番号付きパラメーター(_$0_、_$1_、...)から_argv[]_(プロセスの開始時にコマンドラインパラメーターを含む配列)への明確な類似点があります。配列の最初の要素_argv[0]_は通常、プロセスの名前を保持し、実際の引数は_argv[1]_から始まります。

(通常、そうする必要はありません。 execve(2)の説明 : "_argv[0]_の値すべきファイル名を指します開始されるプロセスに関連付けられている文字列 ")

少なくとも事実上、その規約がシェルに直接コピーされただけだと想像するのは簡単です。

ただし、値は直接コピーされません。少なくとも私のシステムでは、ハッシュバング_./script.sh_を指定して_#!/bin/bash -x_を実行すると開始するシェルプロセスは、パラメーター_/bin/bash_、_-x_、_./script.sh_を取得します。つまり、スクリプトから見て_$0_に移動する値は、シェルプロセスの_argv[2]_に含まれています。

ほとんどの人はコマンド名をそのパラメーターとは異なるものと考えるので、_$0_は機能的にと異なるため、別の方法で呼び出すことも不合理ではありません。

もちろん、命名規則が異なるスクリプト言語を使用することもできます。 Perlは、プログラム名を_$0_と呼ばれる変数に入れ、引数は配列_@ARGV_にインデックスゼロから開始します。つまり、_$ARGV[0]_などです。


とにかく、最も明白な答えは、_$0_は位置パラメータではないと言うことです標準ではそう言っているため

2.5パラメータと変数 の下

2.5.1位置パラメータ

定位置パラメーターは、1桁の0以外の1桁以上の数字で表される10進値で示されるパラメーターです。

2.5.2特殊パラメータ

_#_位置パラメータの10進数に展開します。コマンド名(パラメーター0)は、位置パラメーターではなく特殊パラメーターであるため、「_#_」で指定された数にカウントされません。

_0_(ゼロ)シェルまたはシェルスクリプトの名前に展開されます。

8
ilkkachu

$ 0は実際には定位置パラメーターです(以下のMichael Homerのコメントにも記載されています。POSIXは "... 1〜nの番号が付けられた位置パラメーターとしての引数の名前、およびコマンドの名前(または関数の場合)スクリプト内では、スクリプトの名前)の番号が付けられた位置パラメーターとして "。

これは、予想されるように、呼び出しコマンドの名前を表す位置0のパラメーターです。

これは、同じスクリプトがその呼び出し名に応じて異なる動作をすることを可能にし、同じ実行可能ファイルに複数の機能(シンボリックリンクなど)を持たせることができるため、非常に便利です。これにより、プロセスは呼び出し名を知ることができます。

/ binをざっと見ると、bzcat、bzcmp、bzip2などの多くの例が表示されます。 mdir、mcat、mcd、mdel、...; xz、xzcat、unxz、その他多数。プロセスが実行する機能を認識する方法は、位置パラメータ0をチェックすることです。

注:一部のシェルのマニュアルページでは、用語の扱い方が異なる場合があります。bashのマニュアルページでは位置パラメータではないと記載されており、kshのマニュアルページ(およびPOSIX定義)ではそうであると記載されています。用語の説明に関係なく、(bashとksh)の両方で、$ 0には呼び出しコマンドまたはスクリプトの名前が含まれます。これがインタラクティブシェルの場合、$ 0はプロセス名であるため、シェルの名前(bash、kshなど)を含みます。

4
Marcelo