私の理解によると、globワイルドカードはシェルによって解釈され、シェルは一致するファイル名ごとに指定されたコマンドを実行します。abc1, abc2, and abc3
現在のディレクトリにファイルがあるとします。次に、たとえば、echo abc*
「abc」で始まるファイル名ごとに1回エコーします。
ただし、実行するgrep 'foo' abc*
と、次のように実行されるはずです。
grep 'foo' abc1
grep 'foo' abc2
grep 'foo' abc3
つまり、次の出力を取得する必要があります(すべてのファイルに「foo」という1行が含まれていると仮定します)。
foo
foo
foo
ただし、代わりに次のようになります。
abc1:foo
abc2:foo
abc3:foo
したがって、これには2つの考えられる説明があると思います。まず、どういうわけか、grepはglob式で使用されたことを検出し、一致する前にファイル名を出力することで応答します。次に、複数のファイルをgrepに渡すことができるため、シェルは実際には1つのコマンドのみを実行します。
grep 'foo' abc1 abc2 abc3
ただし、これは、grepが最後に複数のファイルを受け入れるためにのみ機能します。別のコマンドでは1つのファイルしか渡されない可能性があります。したがって、globに一致する複数のファイルに対してコマンドを実行する場合、上記の2番目の方法でglobが機能すると機能しません。
とにかく、誰かがこれにいくつかの光を当てることができますか?
ありがとう!
それがトリックです:コマンドは知りません、それは仕事をするシェルです
たとえば、を考えてみましょうgrep 'abc' *.txt
。システムコールのトレースを実行すると、次のようなものが表示されます。
bash-4.3$ strace -e trace=execve grep "abc" *.txt > /dev/null
execve("/bin/grep", ["grep", "abc", "ADDA_converters.txt", "after.txt", "altera_license.txt", "altera.txt", "ANALOG_DIGITAL_NOTES.txt", "androiddev.txt", "answer2.txt", "answer.txt", "ANSWER.txt", "ascii.txt", "askubuntu-profile.txt", "AskUbuntu_Translators.txt", "a.txt", "bash_result.txt", ...], [/* 80 vars */]) = 0
+++ exited with 0 +++
シェルは*.txt
、.txt
拡張子で終わる現在のディレクトリ内のすべてのファイル名に展開されました。したがって、効果的に、シェルはgrep 'abc' *.txt
コマンドをに変換しgrep 'abc' file1.txt file2.txt file3.txt . . .
ます。したがって、2番目の仮定は正しいです。
最初の仮定は正しくありません-プログラムにはグロブを検出する方法がありません。*
文字列引数としてコマンドに渡すことは可能ですが、それをどうするかを決めるのはコマンドの仕事です。ただし、ファイル名の展開は、すでに述べたように、それぞれのシェルのプロパティです。
ただし、これは、grepが最後に複数のファイルを受け入れるためにのみ機能します。別のコマンドでは、1つのファイルしか渡されない可能性があります。
まさにその通り!プログラムは、受け入れ可能なコマンドライン引数の数を制限しませんが(たとえば、文字列の配列であるCconst char *args[]
やPythonの場合sys.argv[]
)、その配列の長さや、予期しない何かが間違った配列位置にあるかどうかを検出できます。grep
これは行わず、複数のファイルを受け入れます。これは仕様によるものです。
ちなみに、不適切な引用とgrepを使用したグロビングが問題になる場合があります。このことを考慮:
bash-4.3$ echo "one two" | strace -e trace=execve grep *est*
execve("/bin/grep", ["grep", "self_test.sh", "test.wxg"], [/* 80 vars */]) = 0
+++ exited with 1 +++
準備ができていないユーザーは、grepがest
パイプからの文字を含むすべての行に一致することを期待しますが、代わりにシェルのファイル名拡張がひねりを加えます。私はこれがそうする人々でたくさん起こるのを見ましたps aux | grep shell_script_name.sh
、そして彼らは彼らのプロセスが実行されているのを見つけることを期待しています、しかし彼らはスクリプトがあった同じディレクトリからコマンドを実行したので、シェルのファイル名拡張はgrep
コマンドをユーザーが期待したものとは完全に異なって見えるようにしました。
適切な方法は、一重引用符を使用することです。
bash-4.3$ echo "one two" | strace -e trace=execve grep '*est*'
execve("/bin/grep", ["grep", "*est*"], [/* 80 vars */]) = 0
+++ exited with 1 +++
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加