2017年11月5日日曜日

シェルスクリプトで変数に入れたコマンドを実行する方法の比較(evalコマンドなどの動作比較)

シェルスクリプトを作る際に、変数にコマンド文字列を入れて実行したい場合がある。実現方法は複数あるが、今回は以下の3つのパターンの動作について確認をしてみることにした。

 A. 変数をそのまま書く
 B. evalコマンドを使う
 C. ``で変数を囲む

なお、Cの``で変数を囲む方法は、$()で変数を囲むことと同義となる。

比較その①

単純なコマンド+オプション1個の形での実行パターンとして、以下コマンドを変数に入れて実行してみることにする。

# uname -r
------------------------------
3.10.0-514.26.2.el7.x86_64
------------------------------
# com="uname -r"

A. 変数をそのまま書く

# $com
------------------------------
3.10.0-514.26.2.el7.x86_64
------------------------------

結果:実行に成功

B. evalコマンドを使う

# eval $com
------------------------------
3.10.0-514.26.2.el7.x86_64
------------------------------

結果:実行に成功

C. ``で変数を囲む

# `$com`
------------------------------
bash: 3.10.0-514.26.2.el7.x86_64: コマンドが見つかりませんでした...
------------------------------

結果:実行に失敗

これは「uname -r」の実行結果である「3.10.0-514.26.2.el7.x86_64」が、コマンドとして実行されてしまいエラーとなっている。そのため、``の場合はechoを付ける必要がある。

# echo `$com`
------------------------------
3.10.0-514.26.2.el7.x86_64
------------------------------

比較その②

コマンド文字列のオプションをさらに変数に入れた場合の比較もしてみた。「uname -r」の「-r」のオプションを別変数にする形で実行する。

# opt="-r"
# com="uname $opt"

先に結果を述べてしまうと、比較その①の結果と同様となった。

A. 変数をそのまま書く

# $com
------------------------------
3.10.0-514.26.2.el7.x86_64
------------------------------

結果:実行に成功

B. evalコマンドを使う

# eval $com
------------------------------
3.10.0-514.26.2.el7.x86_64
------------------------------

結果:実行に成功

C. ``で変数を囲む

# `$com`
------------------------------
bash: 3.10.0-514.26.2.el7.x86_64: コマンドが見つかりませんでした...
------------------------------

結果:実行に失敗

比較その①で実施した方法と同様にechoを付けてやれば、コマンド実行の結果が表示される。

# echo `$com`
------------------------------
3.10.0-514.26.2.el7.x86_64
------------------------------

比較その③

最後に、パイプを使ったコマンドを実行するパターンとして、以下コマンドを変数に入れた場合の実行結果を比較する。

# ifconfig | grep ens160
------------------------------
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
------------------------------
# com="ifconfig | grep ens160"

A. 変数をそのまま書く

# $com
------------------------------
grep: 不明なホストです
ifconfig: `--help' gives usage information.
------------------------------

結果:実行に失敗

これは実行コマンドが以下の通り解釈されており、"|"などもifconfigコマンドの引数として扱ってしまっていることが原因となる。

# ifconfig "|" "grep" "ens160"
------------------------------
grep: 不明なホストです
ifconfig: `--help' gives usage information.
------------------------------

したがって、パイプやリダイレクトを含むようなコマンドは、この方法では実行不可となる。

B. evalコマンドを使う

# eval $com
------------------------------
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
------------------------------

結果:実行に成功

evalではパイプを含むようなコマンドでも問題なく実行できた。

C. ``で変数を囲む

[root@t1101ce73 ~]# `$com`
grep: 不明なホストです
ifconfig: `--help' gives usage information.

結果:実行に失敗

Aの方法と同じ理由で失敗。

まとめ

簡単なコマンドであれば、どの方法でも期待通りのコマンド実行結果を得ることができるが、パイプやリダイレクトを含むコマンドではevalコマンドを使う必要がある。

1 件のコメント:

  1. com='~/bin/test.sh var'
    として任意のディレクトリからA.変数名をそのまま書く($com)と動かないけど
    B. evalコマンドを使う(eval $com)とすると実行できた。

    返信削除

人気の投稿