パイプラインを使用する必要がある場合と使用しない場合を考えます。
たとえば、pdfファイルを処理する特定のプロセスを強制終了するために、パイプラインを使用しても以下は機能しません。
ps aux | grep pdf | awk '{print $2}'|kill
代わりに、次の方法でしか実行できません。
kill $(ps aux| grep pdf| awk '{print $2}')
または
ps aux | grep pdf | awk '{print $2}'| xargs kill
による man bash
( バージョン 4.1.2
):
The standard output of command is connected via a pipe to the standard input of command2.
上記のシナリオの場合:
grep
の標準入力は、ps
の標準出力です。うまくいきます。awk
の標準入力は、grep
の標準出力です。うまくいきます。kill
の標準入力は、awk
の標準出力です。それはうまくいきません。次のコマンドのstdinは、常に前のコマンドのstdoutから入力を取得しています。
kill
またはrm
で動作しないのはなぜですか?kill
、rm
入力とgrep
、awk
入力の違いは何ですか?プログラムに入力を提供するには、2つの一般的な方法があります。
kill
はコマンドライン引数のみを使用します。 STDINからは読み取りません。 grep
やawk
などのプログラムは、STDINから読み取り(コマンドライン引数としてファイル名が指定されていない場合)、コマンドライン引数(パターン、ステートメント、フラグなど)に従ってデータを処理します。 。
パイプを使用できるのは他のプロセスのSTDINのみで、コマンドライン引数にはパイプできません。
一般的なルールは、プログラムがSTDINを使用して任意の量のデータを処理することです。すべての追加の入力パラメーター、または通常はほとんどない場合は、コマンドライン引数によって渡されます。コマンドラインが非常に長くなる可能性がある場合、たとえばawk
プログラムテキストが長い場合、追加のプログラムファイルからこれらを読み取る可能性があります(awk
の_-f
_オプション)。
プログラムのSTDOUTをコマンドライン引数として使用するには、$(...)
を使用するか、大量のデータの場合はxargs
を使用します。 find
は、これを_-exec ... {} +
_で直接行うこともできます。
完全を期すために:コマンドライン引数をSTDOUTに書き込むには、echo
を使用します。
これは興味深い質問で、Unix/Linuxの哲学の一部を扱っています。
では、grep
、sed
、sort
などのプログラムと、kill
、rm
、ls
などのプログラムの違いは何ですか。二つの側面があります。
最初の種類のプログラムはfiltersとも呼ばれます。これらは、ファイルまたはSTDINから入力を受け取り、それを変更して、主にSTDOUTへの出力を生成します。それらは、ソースおよび宛先として他のプログラムと一緒にパイプで使用されることを意図しています。
2番目の種類のプログラムは入力に作用しますが、それらが与える出力は、多くの場合、入力に関連していません。 kill
は、正常に動作する場合は出力がなく、ls
も動作しません。成功を示すための戻り値があります。それらは通常STDINから入力を受け取りませんが、ほとんどの場合STDOUTに出力を提供します。
ls
のようなプログラムの場合、フィルターアスペクトはそれほどうまく機能しません。入力があることは確かですが(入力は必要ありません)、出力はその入力と密接に関連していますが、フィルターとしては機能しません。ただし、この種のプログラムでは、他の側面も機能します。
フィルターの場合、それらの入力にはセマンティックな意味なしがあります。データを読み取り、データを変更し、データを出力するだけです。これが数値のリスト、一部のファイル名、HTMLソースコードのいずれであるかは関係ありません。このデータの意味は、フィルターに提供するコードyouによってのみ与えられます:grep
の正規表現、awk
のルール、またはPerlプログラム。
kill
やls
などの他のプログラムの場合、それらの入力には意味、表示があります。 kill
はプロセス番号を想定し、ls
はファイルまたはパス名を想定します。それらは任意のデータを処理することができず、意図されていません。それらの多くは、ps
のように、入力もパラメーターも必要としません。通常、STDINからは読み取りません。
おそらく、これら2つの側面を組み合わせることができます。フィルターは、入力がプログラムにとって意味のないプログラムです。
この哲学についてはどこかで読んだと思いますが、現時点では出典を覚えていません。誰かがソースを持っている場合は、自由に編集してください。
そのような「ルール」はありません。一部のプログラムはSTDINから入力を受け取り、一部は受け取りません。プログラムがSTDINから入力を受け取ることができる場合、パイプすることができますが、できない場合はできません。
通常、プログラムが何をするかを考えることで、プログラムが入力を受け取るかどうかを判断できます。プログラムの仕事が何らかの形でファイルのcontentsを操作することである場合(例:grep
、sed
、awk
など)、入力を受け取りますSTDINから。そのジョブがファイル自体(例:mv
、rm
、cp
)またはプロセス(例:kill
、lsof
)を操作することである場合)または、何かについての情報を返す場合(例:top
、find
、ps
)は返されません。
もう1つの考え方は、引数と入力の違いです。例えば:
mv foo bar
上記のコマンドでは、mv
にはそのような入力はありません。それが与えられたことは2つの議論です。それはどちらのファイルに何があるかを知りませんし、気にしません、それらがそれらの引数であることを知っているだけで、それらを操作する必要があります。
一方
sed -e 's/foo/bar/' < file
--- -- ------------ ----
| | | |-> input
| | |------------> argument
| |--------------------> option/flag/switch
|------------------------> command
ここで、sed
には引数と同様に入力が与えられています。入力を受け取るため、STDINから読み取ることができ、パイプすることができます。
引数がbe入力できる場合は、さらに複雑になります。例えば
cat file
ここで、file
はcat
に与えられた引数です。正確には、ファイルnamefile
が引数です。ただし、cat
はファイルの内容を操作するプログラムであるため、その入力はfile
内にあるものすべてです。
これは、プロセスによって行われたシステムコールを追跡するプログラムであるstrace
を使用して説明できます。 cat foo
strace
を介して、ファイルfoo
が開いていることがわかります。
$ strace cat foo 2| grep foo
execve("/bin/cat", ["cat", "foo"], [/* 44 vars */]) = 0
open("foo", O_RDONLY)
上記の最初の行は、プログラム/bin/cat
が呼び出され、その引数はcat
およびfoo
でした(最初の引数は常にプログラム自体です)。その後、引数foo
が読み取り専用モードで開かれました。今、これを
$ strace ls foo 2| grep foo
execve("/bin/ls", ["ls", "foo"], [/* 44 vars */]) = 0
stat("foo", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
lstat("foo", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
write(1, "foo\n", 4foo
ここでも、ls
は自分自身とfoo
を引数として取りました。ただし、open
呼び出しはなく、引数は入力として扱われません。代わりに、ls
はシステムのstat
ライブラリ(stat
コマンドとは異なります)を呼び出して、ファイルfoo
に関する情報を取得します。
要約すると、実行中のコマンドがその入力を読み取る場合は、それにパイプすることができます。読み取らない場合は、パイプできません。
kill
およびrm
にはSTDINは必要ありません。
kill
とrm
の場合、ユーザーはカスタマイズされた情報を引数として提供し、$(cmd)
はcmd
のSTDOUTを取得して情報引数に変換するのに役立ちます。
grep
およびawk
の場合、ユーザーは引数を提供し、さらにSTDIN
またはコマンドによって処理される通常のファイルも提供します。 STDIN
はパイプラインで渡すことができます|
または手動で入力します。
マニュアルまたはソースコードを読んでください。そして、必要なものが見つからない場合は、単純ですが危険なテストを行うことができます。
興味のあるコマンドを、すでに理解している引数を付けて入力し、コマンドが一時停止する(何も起こらない)かどうかを確認します。一時停止した場合、実際にはSTDINを待機しています(cat
とecho
を試して、別のものを確認できます)。手動でCtrl-D
そしてコマンドは先に進み(結果またはエラーを表示)、戻ります。このようなコマンドでは、その状況でSTDINが必要です(引数を指定する必要があります)。
同じコマンドが異なる状況でSTDINを必要としない場合があります(たとえば、cat
はSTDINを待機しますが、cat file.txt
ではありません)。