eval は、与えた文字列をもう一度シェルのコマンドとして解釈して実行します。展開(変数・コマンド置換・パス名展開など)が追加で行われ、結果のコマンドが現在のシェルで走ります。
実務では、getopt の整形結果で set -- を行うときや、生成したコマンド列を最終的に実行したいときに使われます。
構文(Syntax)
eval [ARGUMENT ...]
# 引数が複数なら、スペースで連結した1つの文字列として再解釈される
# 戻り値は「再解釈後に実行された最後のコマンド」の終了ステータス
主なオプション一覧
eval自体に一般的なオプションはありません。実用パターンを「項目」として整理します。
| オプション | 説明 | 使用例 |
|---|---|---|
| (なし) | 文字列を再解釈して実行 | eval 'echo hello' |
| 変数で組み立て | 変数の中身をコマンドとして実行 | cmd='printf "%s\n" hi'; eval "$cmd" |
| 連結評価 | 複数引数は連結して1文字列として評価 | eval echo "$USER" is "$SHELL" |
getopt と併用 | 整形した引数列を位置パラメータへ反映 | eval set -- "$(getopt -o ab: -l alpha,bravo: -- "$@")" |
| 間接参照 | 変数名を変数で受けて参照・代入(POSIX流) | name=HOME; eval "echo \$$name" |
実行例
生成したコマンドを実行(基本)
説明:文字列として組み立てたコマンドを実行します。
コマンド
cmd='echo "Project: $PWD"'
eval "$cmd"
出力例(例)
Project: /home/user/work
getopt と組み合わせて安全に引数を整形
説明:getopt の出力を set -- に流し込み、以降の case で処理。
コマンド
OPTS_SHORT='ab:'
OPTS_LONG='alpha,bravo:'
PARSED="$(getopt -o "$OPTS_SHORT" -l "$OPTS_LONG" -n "$0" -- "$@")" || exit 2
eval set -- "$PARSED"
while true; do
case "$1" in
-a|--alpha) echo alpha; shift;;
-b|--bravo) echo "b=$2"; shift 2;;
--) shift; break;;
esac
done
出力例(例)
alpha
b=42
変数名を変数で参照(間接参照)
説明:$name が指す変数(ここでは HOME)の値を参照します。
コマンド
name=HOME
eval "echo \$$name"
出力例(例)
/home/user
危険例:入力混入で意図しない実行(やってはいけない)
説明:外部入力をそのまま eval へ渡すとコマンド注入の危険があります。
コマンド
user_input='Alice; echo HACKED'
eval "echo Hello, $user_input"
出力例(例)
Hello, Alice
HACKED
外部入力は 決して そのまま
evalに渡さないでください。必要なら厳格なバリデーション・無害化や代替手法を使います。
エラー例:再解釈先が構文エラー
説明:再解釈した文字列がシェル構文として不正だとエラー終了します。
コマンド
eval 'echo $(('
echo $?
出力例(例)
bash: syntax error near unexpected token `newline'
2
関連コマンド
bash -c 'STRING':新しいシェルで文字列をコマンドとして実行(呼び出し元の環境を汚さない)。getopt:引数列の整形に使い、eval set -- "$( ... )"で反映。${!name}(bash拡張):間接展開。evalを使わず変数名から値を参照できる。declare -n ref(bash拡張):名前参照で間接代入/参照を安全に実現。printf -v var ...(bash拡張):文字列の安全な代入。eval "var=..."の代替。xargs:標準入力から受け取ったトークンを安全に引数化してコマンド実行(evalの代替になり得る)。
備考
- セキュリティ:
evalは二重展開を起こすため、外部入力や未検証の文字列を渡すとコマンド注入が極めて起きやすいです。基本方針は「使わない」。代替(配列、間接展開、printf -v、bash -c、xargs)を優先してください。 - 可搬性:
evalは POSIX ユーティリティで、sh互換シェルに広く存在します。 - クォート:
eval "$cmd"のように一重の引数にまとめて渡すのが原則。展開させたい内容は**$cmd内側のクォート**で制御します。 - 戻り値:
eval自身の終了ステータスは、再解釈後に実行された最後のコマンドの終了コードです。if eval ...; then ... fiのように条件判定に使えます。 - デバッグ:実際に何が実行されるか不安なときは、まず
printf '%q\n'で可視化したり、set -x(xtrace)を一時的に有効化して確認します。
参考
- POSIX
eval仕様(The Open Group)
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/eval.html - Bash Reference Manual(Bourne Shell Builtins /
eval)
https://www.gnu.org/software/bash/manual/html_node/Bourne-Shell-Builtins.html#index-eval bash(1)マンページ(組み込みコマンド)
https://man7.org/linux/man-pages/man1/bash.1.html

コメント