はじめに
LinuxのBashでコマンド操作を行なっている際に、コマンドが出力した結果をそのままコマンドとして利用したり、実行したいと思う場面に遭遇する事があるかと思いますが、その場合の対応方法について紹介します。
例えばファイル名のプレフィックスを誤って付与して複数ファイルを生成してしまいファイル名を変更したい場合、リネームするためのコマンドを生成したものの、この後どうやって生成したコマンドを実行しよう...となってしまった場合などが上記に該当します。
$ ls
hoge1_20220530.dmp hoge1_20220530.png hoge1_20220530.txt
$ ls | sed -e 's/^\(.*\)/mv \1 :\1/' -e 's/:hoge1/hoge2/'
mv hoge1_20220530.dmp hoge2_20220530.dmp
mv hoge1_20220530.png hoge2_20220530.png
mv hoge1_20220530.txt hoge2_20220530.txt
$
・コンソールにコマンドを貼り付ける
コマンドの出力結果を一行コピーしてコンソールに貼り付けて実行、終わったら次の一行をコピーしてコンソールに貼り付けて実行...と繰り返し行う事もできますが、大量に行数があった場合に作業が面倒になります。
意外と知られていませんがコンソールにコマンドを貼り付けて実行する場合に複数行のコピー結果をコンソールに貼り付ける事ができます。
また、貼り付けられてたコマンドは上から順番に実行されますので、わざわざ一行一行実行されるのを待つ必要はありません。
上記の例でいうと、コマンド出力結果の下記3行を改行と一緒にコピーしてコンソールに貼り付けを行うと、そのまま3つのコマンドが上から順次実行されて行きます。
mv hoge1_20220530.dmp hoge2_20220530.dmp
mv hoge1_20220530.png hoge2_20220530.png
mv hoge1_20220530.txt hoge2_20220530.txt
1つのコマンドに時間がかかる処理でも同様に実行してくれるので、テキストエディタなどに記載した複数のコマンドを手っ取り早く実行する際にも役に立ちます。
・bash
コマンドを使用する
コマンドを実行する際のShellとして認識されているBashですが、実はbash
というコマンドが用意されており、それを利用してコマンド出力結果を使ってコマンドを実行する事ができます。
具体的にはコマンドの出力結果をパイプ|
で繋いでbash
コマンドに渡す事で、渡された出力結果のテキストをコマンドとして実行してくれます。
$ ls | sed -e 's/^\(.*\)/mv \1 :\1/' -e 's/:hoge1/hoge2/' | bash
$
末尾に | bash
をつけるだけなので簡単でわかりやすくオススメの実行方法です。
・xargs
コマンドを使用する
コマンドの引数を動的に作成して実行するための代表的なコマンドとしてxargs
コマンドがありますが、このコマンドを利用してコマンド出力結果を使ってコマンドを実行する事ができます。
具体的にはコマンドの出力結果をパイプ|
で繋いでxargs
コマンドに通じて一行ずつsh
コマンドの引数として渡す事で、渡された出力結果のテキストをコマンドとして実行してくれます。
$ ls | sed -e 's/^\(.*\)/mv \1 :\1/' -e 's/:hoge1/hoge2/' | xargs -IX sh -c "X"
$
また、せっかくxargs
コマンドを使用するのであればリネームするためのmv
コマンドをxargs
コマンドに持ってくる方がスッキリした記述ができます。
$ ls | sed -e 's/^\(.*\)/\1 :\1/' -e 's/:hoge1/hoge2/' | xargs -L1 mv
$
bash
コマンドの方が簡単でわかりやすいのでわざわざxargs
コマンドを使う必要はありませんが、引数も動的に変える場合や、時間のかかるコマンドを-P
オプションを使用して複数同時に実行する場合などに重宝します。
$ ls | sed -e 's/^\(.*\)/mv \1 :\1/' -e 's/:hoge1/hoge2/' | xargs -P3 -IX sh -c "X"
$
今回は単純に出力結果を使用してコマンドを実行するだけなのでxargs
コマンド自体の詳細な説明は割愛させて頂きますが、非常に便利で強力なコマンドなので興味のある方は是非調べてみてください。
・sed
コマンドを使用する
今回の例でもコマンド出力結果のテキストを加工するために使用したsed
コマンドですが、引数のスクリプトコマンドにe
を指定する事でテキストをコマンドとして実行する事ができます。
$ ls | sed -e 's/^\(.*\)/mv \1 :\1/' -e 's/:hoge1/hoge2/e'
$
上記では置換処理を行なった後にコマンドの実行を行なっていますが、わかりやすくするためにls
という文字列をsed
コマンドに渡し、置換せずに実行したものを下記に記載します。
$ echo ls
ls
$ echo ls | sed 'e'
hoge1_20220530.dmp
hoge1_20220530.png
hoge1_20220530.txt
$
また、簡単な置換処理を行なった後にコマンドを実行したものを下記に記載します。
$ echo ls | sed 's/$/ -a/e'
.
..
hoge1_20220530.dmp
hoge1_20220530.png
hoge1_20220530.txt
$
この様に実行したいコマンドを作成しながら実行もできるので非常に使いやすく、sed
コマンドそのものも非常に強力なため慣れてくると一番活躍する実行方法になるのではないかと思います。
・コマンド置換$()
を使用する
Bashにはコマンドの出力結果を置き換えるコマンド置換($()
)という機能があり、この機能を利用してコマンドの出力結果をそのままコマンドとして実行する事ができます。
$ echo ls | $(cat -)
hoge1.txt hoge2.txt
$
通常コマンド置換は変数にコマンド実行結果を格納するのに使用されますが、この様にコマンド実行結果をそのままコマンドとして使用することもできます。
ただ、一行のコマンドしか実行できず非常にわかり難いため、この方法を使用するより素直にbash
コマンドを使用する方が良いと思います。
・find
コマンドを使用する
コマンドの実行結果をそのままコマンドとして実行する訳ではないのですが、find
コマンドでも見つけたファイルに対してコマンドを実行する事ができます。
例えば先ほどの例で紹介していたファイルのリネームについてもfind
コマンドであればスッキリ記述する事ができます。
$ find ./ -exec rename hoge1 hoge2 "{}" \;
$
この様に、検索したファイルに対してアクションを起こしたい場合はfind
コマンドでできる事が以外と多く、またxargs
コマンドを組み合わせて使うことも多いので参考までに記載しておきます。