一部のコマンドが標準入力から読み取れないのはなぜですか?


19

パイプラインをいつ使用すべきなのか、使用すべきでないのはいつだろうか。

たとえば、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。それは機能しません。

次のコマンドの標準入力は、常に前のコマンドの標準出力から入力を取得しています。

  • killまたはで動作しないのはなぜrmですか?
  • 間の異なる何ですかkillrmと入力grepawk入力は?
  • ルールはありますか?

1
これが答えではないですが、あなたは見ていたいかもしれないpgreppkillkillallのコマンドを。
テルドン

2
@terdon:私はパイプラインの問題を示すために上記のシナリオを使用しているだけでpgrepあり、残りはこれを完全に達成できることを理解しています:)
sylye 14

回答:


17

プログラムに入力を提供する一般的な方法は2つあります。

  • プロセスの標準入力にデータを提供する
  • コマンドライン引数を指定する

killコマンドライン引数のみを使用します。STDINからは読み取りません。以下のようなプログラムgrepawk(何のファイル名は、コマンドライン引数として指定されていない場合)STDINから読み取られ、そのコマンドライン引数(パターン、文、旗、...)に応じてデータを処理します。

パイプできるのは、コマンドライン引数ではなく、他のプロセスのSTDINのみです。

一般的なルールは、プログラムがSTDINを使用して任意の量のデータを処理することです。すべての追加の入力パラメーター、または、通常わずかしか存在しない場合は、コマンドライン引数で渡されます。コマンドラインが非常に長くなる場合、たとえば長いawkプログラムテキストの場合、追加のプログラムファイルからこれらを読み取る可能性があります(-fオプションawk)。

プログラムのSTDOUTをコマンドライン引数として使用するには、$(...)または大量のデータの場合に使用しますxargsfindこれはで直接行うこともでき-exec ... {} +ます。

完全を期すために:コマンドライン引数をSTDOUTに書き込むには、を使用しますecho


1
コマンドが引数のみを取り、STDINは取りませんか?manページから推測したり読んだりするのではなく、体系的またはプログラム的な方法がありますか?マニュアルページを読むだけでは、STDINもマニュアルページの表示方法の引数の一部であるため、コマンドがSTDINを使用できるかどうかについて明確な手がかりを得ることができませんでした。たとえばgzip、概要では、入力としてFILENAMEを使用する必要があるとは言いませんでした。私はそれを決定するためのより体系的な方法があることを探しています。
シリー14

一部のコマンドには「stdin」(または「stdout」)を意味する「-」引数もあります。
エマニュエル14

xargs「コマンドライン引数にパイプする」ことを正確に許可しませんか?
T.バーロン14

@ T.Verronはい、これはのタスクですxargs。必要に応じてコマンドを複数回呼び出し(コマンドラインのサイズが制限されます)、他の多くのオプションがあります。
ジョフェル14

2
説明のテキストは、プログラムの使用方法を説明します。たとえば、gzipは次のように述べています。「gzipプログラムは、Lempel-Zivコーディング(LZ77)を使用してファイルを圧縮および解凍します。ファイルが指定されていない場合、gzipは標準入力から圧縮、または標準出力に解凍します。」マニュアルページに標準入力が記載されていない場合、それは使用されません。
アランシュトコ14

16

これは興味深い質問であり、Unix / Linux哲学の一部を扱っています。

だから、のようなプログラムの違いは何ですかgrepsedsortそして一方ではkillrmls一方で?2つの側面があります。

フィルタ様相

  • 最初の種類のプログラムは、フィルターとも呼ばれます。ファイルまたはSTDINのいずれかから入力を受け取り、それを変更して、主にSTDOUTへの出力を生成します。これらは、ソースおよび宛先として他のプログラムとともにパイプで使用されることを意図しています。

  • 2番目の種類のプログラムは入力に作用しますが、それらが与える出力は多くの場合入力に関連していません。kill定期的に動作する場合は出力がありませんls。成功を示す戻り値があります。通常はSTDINから入力を受け取りませんが、ほとんどはSTDOUTに出力を渡します。

のようなプログラムの場合ls、フィルターのアスペクトはそれほどうまく機能しません。確かに入力を持つことができますが(入力は必要ありません)、出力はその入力に密接に関連していますが、フィルターとしては機能しません。ただし、この種のプログラムでは、他の側面は引き続き機能します。

セマンティック様相

  • フィルターの場合、入力にはセマンティックな意味はありません。データを読み取り、データを変更し、データを出力するだけです。これが数値のリストであるか、一部のファイル名であるか、HTMLソースコードであるかは関係ありません。このデータの意味は、フィルターに提供するコード、つまり正規表現、規則、またはPerlプログラムによってのみ与えられますgrepawk

  • 他のプログラムでは、好きkillか、lsその入力があり、意味表記をkillプロセス番号、lsファイル名またはパス名が必要です。任意のデータを処理することはできず、意図されていません。それらの多くは、などの入力やパラメーターさえ必要としませんps。通常、STDINからは読み取りません。

おそらく、これらの2つの側面を組み合わせることができます。フィルターは、入力がプログラムにとって意味的な意味を持たないプログラムです。

私はどこかでこの哲学について読んだと確信していますが、現時点ではソースを覚えていません。申し訳ありません。誰かがいくつかのソースを提示している場合は、気軽に編集してください。


5

そのような「ルール」はありません。STDINから入力を受け取るプログラムとそうでないプログラムがあります。プログラムがSTDINから入力を取得できる場合、パイプで接続できますが、そうでない場合は接続できません。

通常、プログラムが何をするかを考えることで、プログラムが入力を受け取るかどうかを判断できます。プログラムの仕事は何とか操作することであるならば内容ファイル(例えばのgrepsedawkなど)を、それが正常にSTDINからの入力を取ります。その仕事は、ファイル自体を操作することであるならば(例えばmvrmcp)またはプロセス(例えばkilllsof)か何か(例えば、約復帰情報にtopfindps)それはしていません。

別の考え方は、引数と入力の違いです。例えば:

mv foo bar

上記のコマンドでmvは、そのような入力はありません。与えられているのは2つの引数です。どちらのファイルに何が含まれているかを知らず、気にしません。それらが引数であることを知っているだけで、操作する必要があります。

一方

sed -e 's/foo/bar/' < file
--- -- ------------   ----
 |   |       |          |-> input
 |   |       |------------> argument        
 |   |--------------------> option/flag/switch
 |------------------------> command

ここでsedは、入力と引数が与えられています。入力を受け取るので、STDINから読み取ってパイプすることができます。

引数ができたときには、より複雑になること入力。例えば

cat file

ここに、fileに与えられた引数がありますcat。正確には、ファイル fileが引数です。ただし、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が呼び出され、その引数がcatandであったことを示しています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

要約すると、実行中のコマンドがその入力を読み取る場合は、パイプすることができます。そうでない場合はできません。


0
  • killまたはrmで動作しないのはなぜですか?

killrmSTDINは必要ありません。

  • kill、grepを使用したrm入力、awk入力の違いは何ですか?

以下の場合killrm、ユーザーが引数としてそのカスタマイズした情報を提供する、と$(cmd)のSTDOUTを取ることができますcmdし、それinfo引数を変換します。

以下の場合grepawk、ユーザーはまた、引数を提供し、加えて、STDINまたはコマンドによって処理される通常のファイル。 STDINパイプライン|または手動入力で渡すことができます。

  • ルールはありますか?

マニュアルまたはソースコードを読んでください。必要なものが見つからない場合は、単純だが多分危険なテストを作成できます。

興味のあるコマンドを、既に理解している引数を付けて入力し、コマンドが一時停止する(何も起こらない)かどうかを確認してください。それは一時停止した場合、それは実際に(あなたが試すことができSTDINを待っているcatと、echo別のを見て)。手動で入力するCtrl-Dと、コマンドは先に進み(結果またはエラーを表示)、戻ります。そのようなコマンドには、その状況でSTDINが必要です(引数を指定して)。

同じコマンドは、異なる状況でSTDINを必要としない場合があります(たとえば、catSTDINを待機しますが、待機しcat file.txtません)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.