web-dev-qa-db-ja.com

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

パイプラインを使用する必要がある場合と使用しない場合を考えます。

たとえば、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で動作しないのはなぜですか?
  • killrm入力とgrepawk入力の違いは何ですか?
  • ルールはありますか?
20
sylye

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

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

killはコマンドライン引数のみを使用します。 STDINからは読み取りません。 grepawkなどのプログラムは、STDINから読み取り(コマンドライン引数としてファイル名が指定されていない場合)、コマンドライン引数(パターン、ステートメント、フラグなど)に従ってデータを処理します。 。

パイプを使用できるのは他のプロセスのSTDINのみで、コマンドライン引数にはパイプできません。

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

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

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

17
jofel

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

では、grepsedsortなどのプログラムと、killrmlsなどのプログラムの違いは何ですか。二つの側面があります。

filterアスペクト

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

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

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

セマンティックアスペクト

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

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

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

この哲学についてはどこかで読んだと思いますが、現時点では出典を覚えていません。誰かがソースを持っている場合は、自由に編集してください。

17
Dubu

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

通常、プログラムが何をするかを考えることで、プログラムが入力を受け取るかどうかを判断できます。プログラムの仕事が何らかの形でファイルのcontentsを操作することである場合(例:grepsedawkなど)、入力を受け取りますSTDINから。そのジョブがファイル自体(例:mvrmcp)またはプロセス(例:killlsof)を操作することである場合)または、何かについての情報を返す場合(例:topfindps)は返されません。

もう1つの考え方は、引数と入力の違いです。例えば:

mv foo bar

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

一方

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

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

引数がbe入力できる場合は、さらに複雑になります。例えば

cat file

ここで、filecatに与えられた引数です。正確には、ファイルnamefileが引数です。ただし、catはファイルの内容を操作するプログラムであるため、その入力はfile内にあるものすべてです。

これは、プロセスによって行われたシステムコールを追跡するプログラムであるstraceを使用して説明できます。 cat foostraceを介して、ファイル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に関する情報を取得します。

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

5
terdon
  • Killまたはrmで動作しないのはなぜですか?

killおよびrmにはSTDINは必要ありません。

  • Kill、rm入力、grep、awk入力の違いは何ですか?

killrmの場合、ユーザーはカスタマイズされた情報を引数として提供し、$(cmd)cmdのSTDOUTを取得して情報引数に変換するのに役立ちます。

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

  • ルールはありますか?

マニュアルまたはソースコードを読んでください。そして、必要なものが見つからない場合は、単純ですが危険なテストを行うことができます。

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

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

0
Alex Huang