かすみん日記

暇なときに何か喋ります

なぜxargsが必要か【シェルスクリプト】

間違い探し

まずは hello という内容のファイル a.txt を作成しておく。

% echo hello > a.txt
% cat a.txt
hello

ここで、ファイル名 a.txt をパイプで与えて、結果的に cat a.txt を実行するようにしたいとする。

以下のようにコマンドを実行した。

% echo a.txt | cat
a.txt

あれれ、a.txt の中身の hello じゃなくて、単に文字列 a.txt が表示されてしまったぞ。

パイプの左側のコマンドの標準出力を、パイプの右側のコマンドに標準入力として与えているはずだが、なぜ。

答え合わせ

パイプで左から右に渡している「もの」は、標準出力を「箱(ファイルのようなもの?)」に入れたものになっている。

つまり、出力である「文字列」を「箱」に入れて、「箱」ごとパイプの右へ渡している感じだろうか。

一方、普段 cat a.txt などのようにしてコマンドラインで与えている引数は、「文字列の入った箱(ファイル)」ではなく、単なる「文字列」である。

パイプの左側の標準出力を「文字列」としてそのまま右側に渡したいのであれば、それを「箱」から出してあげなければならない。

そして、それをしてくれるコマンドが xargs である。

つまり、下記のように修正すれば良い。

% echo a.txt | xargs cat
hello

こうすると、ちゃんと a.txt の中身を cat コマンドで表示できた。

具体例と説明?

と言われても、いまいちわからん。結局何が違うのか。

xargs があるのとないので、出力がどう違うか、いくつか見てみる。

まず準備。

% echo hello > a.txt

% ls
a.txt

% cat a.txt
hello

いくつかサンプル。

% echo a.txt | cat 
a.txt

% echo a.txt | xargs cat
hello

% echo a.txt | echo     


% echo a.txt | xargs echo
a.txt

% cat a.txt | cat
hello

% cat a.txt | xargs cat
cat: hello: No such file or directory

% cat a.txt | echo     


% cat a.txt | xargs echo
hello

echo a.txt | cat -> a.txt

まず echo a.txt | cat では、a.txt という「文字列が入った箱」が引数として cat に渡される。

これは、a.txt という内容のファイルを cat に渡しているのと同じ意味である。

つまり、 a.txt が出力されることになる。

echo a.txt | xargs cat -> hello

echo a.txt | xargs cat では、a.txt という「文字列」が引数として cat に渡される。

これは、cat が引数として与えられた a.txt という名前のファイルの中身を表示するので、hello が表示される。

echo a.txt | echo -> ""

echo a.txt | echo を実行すると何も表示されない。

これは、a.txt という文字列が入った箱を echo に渡していることになっている。

echo は引数の「文字列」を表示するコマンドなので、「箱」を渡しても何も起きない。つまり、何も表示されない。

echo a.txt | xargs echo -> a.txt

echo a.txt | xargs echo では a.txt が表示される。

これは、「箱」から出した a.txt という「文字列」が echo に渡されるので、a.txt が表示される。

cat a.txt | cat -> hello

cat a.txt | cat を実行すると、a.txt の中身である hello が表示される。

パイプの左側の cat a.txthello が出力されるが、それをまた「箱」に入れ直してからパイプの右側の cat に渡す。

なので、右側で再び「箱」から中身を取り出して hello が表示される。

cat a.txt | xargs cat -> ERROR

cat a.txt | xargs cat では、エラーが表示される。

hello を「箱」に入っていない「文字列」としてパイプの右側の cat に渡すので、「hello というファイルなんてないぞ」と怒られる。

cat a.txt | echo -> ""

cat a.txt | echo を実行しても何も表示されない。

これも、パイプの右側の echo に「文字列」ではなく「箱」を渡しちゃってるので、表示するものがないためである。

cat a.txt | xargs echo -> hello

cat a.txt | xargs echo を実行すると hello が表示される。

パイプの左側の出力である hello を「箱」に入れずに「文字列」として右側の echo に渡しているので、hello は表示される。

おわりに

私もよくわからなくて困っていたら、xargs を付ければ良いとTwitterで教えてもらった。

なぜ xargs が必要なのかはわかったが、パイプのデフォルトで xargs を付けてくれればいいのにと思っている。

なぜパイプを通すときに、標準出力の「文字列」を「箱(ファイル? 配列?)」に入れる必要があるのだろうか。

あと便宜上「箱」と書いてきた「もの」の名前を知っている人がいたら教えて欲しいです。

man xargs のマニュアルとかでは「string」と「argument」という言葉が出ていたが、「string」はこの記事でいう「文字列を箱に入れたもの」に対応していて、データ構造的に配列っぽいものだと思うのだが、文字列と呼んでいいのかわからない。

そもそも「ファイル」が一体何者なのか知らない。

まあそんな感じですた。