シェルスクリプトで、パイプの後に xargs を使って処理を行うことがあります。
あまりこの使い方がピンと来ていなかったのですが、改めて man を読むとポイントは2つかなと思いました。
xargs とは
xargs は、 man によると “xargs – 標準入力を読み込んでコマンドラインを作成し、それを実行する” とあります。
ここから、以下の2つがポイントになります。
- 標準入力を読み込む→パイプが有用
- コマンドラインを作成する→コマンドの引数となる
xargs の基本形
xargs は以下のように使うことになります。
(コマンド1) | xargs コマンド2
これだと分かりづらいので、例を挙げます。
拡張子 .tmp がついているファイルを見つけて、削除したいとします。
まず、 カレントディレクトリ以下に、 “.tmp” がついているファイルは以下で見つけることができます。
find . -name '*.tmp'
この結果を削除したいとします。
この時、
rm (findの結果)
とすれば消せるわけです。
そこで、xargsを使うと、rm の後に、パイプ前の find の結果を引数として渡してあげることができます。
find . -name '*.tmp' | xargs rm
引数を明示しなければいけない場合
引数を明示するのは、コマンドが複数の引数をとる場合です。
たとえば、 cp は2つの引数をとります。
今、find の結果を、temp というディレクトリにコピーしたい場合は、 ” -I {}” で
標準入力から受け取った各行を {} という記号で置き換えることを指定し、実際に引数に入るところに {} を置きます。
つまり、以下のようになります。
find . -name '*.tmp' | xargs -I {} cp -r {} temp
ちなみに、find の場合は xargs を使わなかったとしても、
find . -name '*.tmp' -exec rm {} \;
find . -name '*.tmp' -exec cp {} temp \;
とすることで同様の結果を得ることができますが、xargs は find 以外のコマンドに対しても適用できます。
xargs の実践例
Dockerのコンテナを作成している場合、ビルド中にエラーを起こすとTAGが
ひとつならばいいのですが、それを一気に消したいと思いました。
これを以下で達成できました。
docker image ls | grep none | awk '{ print $3 }' | xargs docker image rm
簡単に解説します。
- “docker image ls” は コンテナイメージを列挙します。
REPOSITORY TAG IMAGE ID CREATED SIZE
container1 latest 608d1c44a054 2 hours ago 55.4GB
container2
container3 latest 65c0b7b9a21f 21 hours ago 43.7GB
container4
- “docker image ls | grep none” で、 none が入っているもののみ表示されます。
container2
container4
- “docker image ls | grep none | awk ‘{ print $3 }'” で、 3列めの情報のみ表示されます。
33f22ef999ce
e1bb0a89e972
- 最後に、これを ” |xargs docker image rm” に入れることで以下が実行されることになります。
docker image rm 33f22ef999ce e1bb0a89e972
ポイントは、xargs で受けるのは引数のリストとなるということでしょうか。
このように、パイプで受けること、引数の場所を意識することで、 xargs のポイントがわかった気がしました。