2016-05-21 12 views
4

私はargv [0]/$ 0の値を非常に慎重に模倣したbashラッパースクリプトを書こうとしています。私は、ラッパーのargv [0]値で別のプログラムを実行するためにexec -aを使用しています。私は時々bashの$ 0がCプログラムのargv [0]と同じ値を与えないことが分かっています。ここではCとbashの両方の違いを示して簡単なテストプログラムです:bashでArgv [0]を慎重に模倣する

int main(int argc, char* argv[0]) 
{ 
    printf("Argv[0]=%s\n", argv[0]); 
    return 0; 
} 

#!/bin/bash 
echo \$0=$0 

バイナリへのフル(絶対または相対)パスでこれらのプログラムを実行しているとき、彼らは振る舞います同じ:

$ /path/to/printargv 
Argv[0]=/path/to/printargv 

$ /path/to/printargv.sh 
$0=/path/to/printargv.sh 

$ to/printargv 
Argv[0]=to/printargv 

$ to/printargv.sh 
$0=to/printargv.sh 

しかし、彼らはパスであるかのようにそれらを呼び出すときに、私が取得異なる結果:

$ printargv 
Arv[0]=printargv 

$ printargv.sh 
$0=/path/to/printargv.sh 

つの質問:

1)は、これが説明できる行動を意図した、またはこれはバグですか? 2)argv [0]を慎重に模倣するという目的を達成する「正しい」方法は何ですか?

編集:typos。あなたはここで見ている何

答えて

2

bashexecve(少なくとも、それはLinuxFreeBSDに文書化されて、私は他のシステムは同様の文書を持っていると推定)の文書化動作であり、argv[0]が構築されるさまざまな方法を反映しています。

提供されたコマンドラインから、さまざまな拡張を実行し、必要に応じて単語を再分割した後に、Bash(ほかのシェルと同様)がargvを構成します。最終結果は、あなたが入力したとき

printargv 

argv{ "printargv", NULL }のように構成されていることであり、あなたが

to/printargv 

argvを入力すると{ "to/printargv", NULL }として構成されています。だからそこに驚きはない。

(どちらの場合も、そこにコマンドライン引数されていた、彼らは位置1から始まるargvに登場しているだろう)しかし、実行パスはその時点で発散します。コマンドラインの最初の単語に/が含まれている場合は、相対または絶対のいずれかのファイル名であるとみなされます。シェルはこれ以上の処理を行いません。指定されたファイル名がfilenameの引数で、argvの配列がargvの引数として構築されているだけで、execveが呼び出されます。この場合、argv[0]は正確filename

に対応するが、コマンドにはスラッシュを持っていないとき:

printargv 

シェルは、より多くの作業を行います。

  • まず、それはかどうかをチェック名前がユーザー定義のシェル関数である場合そうであれば、それは配列から既に取り出された$1...$nを使って実行します。 ($0は引き続きスクリプト呼び出しからargv[0]になります)。

  • 次に、名前が組み込みのbashコマンドであるかどうかを確認します。そうであれば、それを実行します。組み込み関数がコマンドライン引数とどのように相互作用するかは、この回答の対象外であり、実際にユーザーが見ることはできません。

  • 最後に、$PATHのコンポーネントを検索し、実行可能ファイルを検索することによって、コマンドに対応する外部ユーティリティを見つけようとします。見つかった場合は、execveを呼び出し、見つかったパスにfilename引数を指定しますが、コマンドの単語からなるargv配列を使用します。この場合、filenameargv[0]はdo ではなく、に対応しています。

したがって、両方の場合において、シェルは、filename引数とargv引数として単語分割コマンドとしてファイルパス(おそらく相対)を提供する、execveを呼び出してしまいます。

指定されたファイルが実行可能イメージの場合は、それ以上のことは言いません。イメージはメモリにロードされ、mainが提供されたargvベクトルで呼び出されます。 argv[0]は、最初に入力されたものだけに応じて、単一の単語または相対パスまたは絶対パスになります。

しかし、指定されたファイルがスクリプトの場合、ローダーはエラーを生成し、execveはファイルがシバン(#!)で始まるかどうかを確認します。 (POSIX 2008年以来、execveはまた、シェバングラインとして#!/bin/shを持っていたかのように、システムのシェルを使用してファイルをスクリプトとして実行しようとします。)

はここでLinux上execveのドキュメントです:

 #! interpreter [optional-arg] 

インタプリタは、実行可能ファイルの有効なパス名でなければなりません:インタプリタスクリプトが許可有効になっており、その最初の行の形式ですが、実行持つテキストファイルです。 execveのfilename引数は()インタプリタスクリプトを指定している場合、インタプリタは、次の引数で呼び出されます:arg...は一連の単語である

 interpreter [optional-arg] filename arg... 

argv[1]から始まる、execve()argv引数によって指さ。上記では、filename引数はexecveからfilename引数であることを

注意。シェバングライン#!/bin/bashを考えると、私たちは今、argv[0]が効果的に消滅していることに注意してください

/bin/bash to/printargv   # If the original invocation was to/printargv 

または

/bin/bash /path/to/printargv  # If the original invocation was printargv 

のいずれかを持っています。

bashこのファイルでスクリプトを実行します。スクリプトを実行する前に、$0に指定されたファイル名の引数(to/printargvまたは/path/to/printargv)を設定し、元のコマンドラインのコマンドライン引数からコピーされた残りの引数に$1...$nを設定します。要約すると

あなたはスラッシュなしでファイル名を使用して、コマンドを呼び出す場合、:

  • ファイル名は、実行可能イメージが含まれている場合は入力されたとして、それはコマンド名としてargv[0]が表示されます。

  • ファイル名にシバン行のbashスクリプトが含まれている場合、スクリプトファイルには実際のパスとして$0が表示されます。

あなたはスラッシュとファイル名を使用してコマンドを起動した場合は入力されたとして、両方のケースでは、(相対的かもしれないが、明らかに常にスラッシュを持っています)ARGV [0]ファイル名として表示されます。

一方、シェルインタープリタを明示的に起動してスクリプトを呼び出すと(bash printargv)、スクリプトには入力されたとおりにファイル名として$0が表示されます。これは相対的であるだけでなく、スラッシュも含まれません。

これは、あなたが模倣したいスクリプトをどのような形で呼び出すかを知っている場合にのみ、 "注意深くargv [0]"を模倣できることを意味します。

ユニットテストでこれを行う場合は、どの値をargvとして指定するかを指定する必要があります[ 0]。 $0を解析しようとする多くのシェルスクリプトは、それがファイルパスであると仮定します。彼らはそれをするべきではないかもしれないので、それをするべきではありませんが、そこにあります。あなたはそれらのユーティリティを喫煙したい場合は、ごみの値を$0としてください。それ以外の場合は、デフォルトとしてスクリプトファイルへのパスを指定することをお勧めします。

+0

返信いただきありがとうございます。 printargs.shは確かにシバンを持っています。私は2行のソースコードを投稿しました。 これは依然として疑問の重要な部分を残しています:$ argv [0]をbashスクリプトで正確に模倣する正しい方法は何でしょうか? –

+0

@jason、ええ、申し訳ありませんが、私は中断されました。私は数時間で答えを終わらせます。 – rici

+0

@ jason:OK、答えを書き換えました。それが役に立てば幸い。私はargv [0]がこれかもしれないし、そうかもしれないし、理想的にはbashスクリプトがどちらかで動作するという "正しい方法"があるとは思わない。だから、もしあなたがテストしているなら、$ 0のさまざまな値を使ってスクリプトをテストするべきです。あなたがそれに妥当なものを与えようとしているだけの場合は、完全な絶対ファイル名を使用することをお勧めします。詳細な返信をいただきありがとうございます。 – rici

関連する問題