通常、$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
プログラムの動作を定義することです(laまたはで呼び出されますbash
)。ただし、ここではコマンド文字列でのみ表示され、プログラムが表示するコマンド文字列では呼び出すことができないため、これは不可能です。他の用途は思い出せないので説明できませんね。sh
vim
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
すべてのシェルがこれを行うわけではありません。 Bourne Shellがやりました。 Korn(およびAlmquist)シェルは最初の引数を使用するように選択します$1
。 POSIXは最終的にBourneアプローチを採用したので、ksh
デリバティブはash
後でこのアプローチに戻りました(詳細は次を参照)。http://www.in-ulm.de/~mascheck/various/find/#shell)。これは、長い間sh
(Bourne、Almquist、またはKornシェルベースのシステムに応じて)最初の引数が入っているかどうかがわからないため、$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
答え2
この行動はPOSIXで定義:
sh -cコマンド名[パラメータ...]
command_string オペランドからコマンドを読み込みます。特殊パラメータ0の値を設定します(参照:特殊パラメータ)残りのパラメータオペランドから順に、command_nameオペランドと位置パラメータ($ 1、$ 2など)の値から始めます。
この動作を望む理由は次のとおりです。これにより、スクリプトと文字列の間隔が削除されます-c
。動作を変更せずに2つの間で直接変換できます。他の分野では、これらのことが同じであることに依存します。
これは、プログラムパラメータが機能する一般的な方法にも適しています。これは最終的に次のいずれかを呼び出すことで発生します。exec
ここで最初に提供された引数も同様で$0
あり、その引数が実行中の実行ファイルと同じ場合がよくあります。しかし、時にはそこに特別な値が必要で、それを得るための別の方法がない場合もあります。パラメータが存在することを考慮すると、パラメータは何かにマッピングされ、ユーザーはそれが何であるかを設定できる必要があります。
この一貫性(そして可能な歴史的思考)があなたが見つけた状況につながります。