bashのコマンド置換で複数行を処理したい
3行まとめ
- bash(POSIXシェル)のコマンド置換を使うと、コマンド出力をコマンドとして実行させられて便利
- 入れ子にできるため、$()がおすすめ
- 出力が複数行の場合は、while readなどで1行ずつ取り出して$()に流す
コマンド置換の例
※確認環境はRed Hat Enterprise Linux Workstation release 6.8 (Santiago)です。
bashのコマンド置換を使うと、コマンド出力をコマンドとして実行させることができます。
以下例を見てみましょう。通常、echoの後に文字列を続けて入力するとその文字列がそのまま返ってきます。
$ touch hoge
$ ls -la hoge
-rw-rw-r--. 1 testuser testuser 0 3月 22 11:07 2018 hoge
$ echo chmod 666 hoge
chmod 666 hoge
次のように、この文字列を$()でくくってあげると、くくられた文字列をコマンドとして解釈・実行させることができます。これがコマンド置換になります。
$ touch hoge
$ ls -la hoge
-rw-rw-r--. 1 testuser testuser 0 3月 22 11:07 2018 hoge
$ echo $(chmod 666 hoge)
$ ls -la hoge
-rw-rw-rw-. 1 testuser testuser 0 3月 22 11:07 2018 hoge
実現方法としては、以下2通りあるのですが、$()で実現する方をお勧めします。
- `コマンド`
- $(コマンド)
$()を使うメリットとしては以下があります。
- 入れ子にできる
コマンド出力が複数行に渡る場合
シェルの出力結果をコマンド置換したい場合は、$(./test.sh)などとします。出力が1行しかない場合は何も考えなくてもよいのですが、複数行に渡る場合工夫が必要です。
次のようなシェルをコマンド置換するケースを考えてみましょう。
#!/bin/sh
TARGET="hoge"
echo "chmod 700 ${TARGET}"
echo "date"
そのまま実行すると以下のように表示されます。
$ ./test.sh
chmod 700 hoge
date
コマンド置換してみると、dateまで含めてchmodの引数として処理されてしまっています。うまくないです。
$ $(./test.sh)
chmod: cannot access `date': そのようなファイルやディレクトリはありません
for でコマンドの結果を取り出して$()に渡してみると、こうなりました。
$ for v in $(./test.sh); do echo $($v); done
chmod: missing operand
詳しくは `chmod --help' を実行して下さい.
コマンドが見つかりません。
コマンドが見つかりません。
2018年 3月 22日 木曜日 14:26:36 JST
コマンド置換せずに出力させてみると、空白で分割されてしまっているようです。(IFSを設定してあげればうまくいくかもしれない)
$ for v in $(./test.sh); do echo $v; done
chmod
700
hoge
date
while readで1行ずつ取り出して$()に渡してあげると、うまくいきました。
$ ./test.sh | while read f; do $(echo $f); done
2018年 3月 22日 木曜日 14:29:02 JST
$ ls -la hoge
-rwx------. 1 testuser testuser 0 3月 22 11:07 2018 hoge
while readで取り出される値を1つずつ見てみると、1行ずつ取り出されていますね。
$ ./test.sh | while read f; do echo $f; done
chmod 700 hoge
date
コマンド置換の際、改行文字の取り扱いには注意ですね。ヘルプより抜粋ですが、以下のような動きになります。
- 末尾の改行文字が削除される
- 文字列の途中にある改行文字は削除されませんが、単語分割の際に削除されることがある
改行を残したければ、"$(コマンド)"というような記載になります。1
参考
- スクリプトやコマンドの実行結果をコマンドとして実行するメモ(バッククオート``や$( )を使おう)
- 【bash】行ごとに処理する - Qiita
- Shell Command Language
- bash Tips - コマンド置換と算術式展開、パラメータ展開 - Qiita