web-dev-qa-db-ja.com

Linuxで検索結果をrmにパイプできないのはなぜですか?

これがヌービーの質問であるが、良い答えが見つからない場合は申し訳ありません。

私が使用できるものを見つけて削除する

find . -name ".txt" -exec rm "{}" \;

しかし、なぜ私は結果をrmにパイプするだけではいけないのですか

find . -name ".txt" | rm 

私はそれをgrepにパイプするように

find . -name ".txt" | grep a

私はどこかからrmがstdinから入力を受け取らないことを読んだので、パイプすることはできませんが、それはどういう意味ですか? rm a.txtと入力すると、正しくgrepできるように標準入力から読み取りますか?または、stdinとコマンドラインに違いがありますか。助けて!

45
user1297061

@Alex Gitelmanの答えを拡張するには、はい、「標準入力」とコマンドラインには違いがあります。

rm a.txt b.txt c.txtと入力すると、rmの後にリストするファイルはargumentsと呼ばれ、特別な変数(argvと呼ばれる)を介してrmが使用できるようになります。一方、標準入力は、stdinという名前のファイルのようなUnixプログラムに見えます。プログラムは、ディスク上の通常のファイルを開いてそこから読み取る場合と同じように、この「ファイル」からデータを読み取ることができます。

rmは、他の多くのプログラムと同様に、コマンドラインから引数を受け取りますが、標準入力は無視します。好きなものをパイプで送ることができます。そのデータを破棄するだけです。そこでxargsが役立ちます。標準入力の行を読み取り、コマンドライン引数に変換するため、データを別のプログラムのコマンドラインに効果的にパイプできます。巧妙なトリックです。

例えば:

find . -name ".txt" | xargs rm
find . -name ".txt" | grep "foo" | xargs rm  

改行またはスペースを含むファイル名がある場合、これは正しく機能しないことに注意してください。改行またはスペースを含むファイル名を処理するには、代わりに使用する必要があります。

find . -name ".txt" -print0 | xargs -0 rm

これは、findに、改行ではなくヌル文字で結果を終了するように指示します。ただし、grepは以前のようには機能しません。代わりにこれを使用してください:

find . -name ".txt" | grep "foo" | tr "\n" "\0" | xargs -0 rm

今回はtrを使用して、すべての改行をヌル文字に変換します。

90
Tim Pierce

"検索結果をrmにパイプできない理由"

何かをプログラムにパイプすると、パイプがキーボード入力を置き換えます。これを念頭に置いて、次の質問を自問してください:キーボードでrmはどうしますか?キーストロークを削除しますか? (確かに少しばかげている)インタラクティブな制御を受け入れますか? (rmは、確認が必要な場合を除いて対話型ではありません。確認は実際にパイプで指定できます。)

実際のところ、rmが既に実行されている場合、ファイルを削除するコマンドを入力することはできません。したがって、パイプでも実行できません。

キーボードと画面の組み合わせがパイプに置き換わることを念頭に置いておくと、物事はすぐに論理的に見えます。

今度はその逆です。データストリームをgrepにパイプできます。それは、代わりにgrepにキーボードからのキーストロークを入力データとして読み取らせることができるということですか?

はい!それは実際にネイティブで(パイピングなしで)行うことです。

(b.t.w. grepに検索引数をパイプしたり入力したりできないことに注意してください)

これで、なぜca n't rmにパイプするandがコマンドライン引数として機能することを期待するのかがわかりました。

tl; dr:

NIXの哲学によるプログラムの構造:
ファイルイン、ファイルアウト、キーボードイン、スクリーンアウト。->パイプはキーボードとスクリーンのみを置き換えます。

5
thom

パイプは、最初のコマンドの出力を2番目の標準入力に送信します。 rmは標準入力を受け入れないため、パイプを使用できません。 xargsを使用して同じ効果を得ることができます。 xargsの例は、具体的には xargsのマニュアルページ にあります。

4
Alex Gitelman

パイプを使用しない代替案:

xargs rm -f <<< $(find . -name ".txt")
2