Memoize |
BasicWerk
EC Support
Technique
Facebook
|
20140809212217_shell_script_function_and_eval |
|
shell_script_function_and_eval
% ls
file_1 file_2 file_3 other_1 other_2 other_3
% fname="file"
# これは fname を展開した後、単なる文字列として file_* が残ってしまいパターンマッチが動作しない
% ls "${fname}_*"
ls: file_*: No such file or directory
# 同じ理屈でこうしたところで動かない
% ls `echo "${fname}_*"`
ls: file_*: No such file or directory
# これは動く
% ls ${fname}_*
file_1 file_2 file_3
# 別の見方をすると、これは動くけど
% eval "ls ${fname}_*"
file_1 file_2 file_3
# これは動かないってことだ
% eval "ls \"${fname}_*\""
ls: file_*: No such file or directory
クォートの仕方一つで、文字列として評価されて終了するか、コマンドやパターンマッチとして評価されるか違ってくる。
そこの違いを踏まえて、function に(文字列やファイルではなく)コマンドを引数として渡してみよう。
# この単純な関数は、
function e0() {
$1
}
# 引数なしの ls を受け取った時はちゃんと動くけど、
% e0 ls
file_1 file_2 file_3 other_1 other_2 other_3
# ls が引数を伴っているときは、$1 しか評価されない(=$2は捨てられる)ので
# 単なる ls として評価される
% e0 ls ${fname}_*
file_1 file_2 file_3 other_1 other_2 other_3
# そして当然これは単なる文字列に評価されるから動かない
% e0 "ls ${fname}_*"
e0:1: command not found: ls file_*
# 文字列の塊として渡されたコマンドラインを実行したくば eval を使う
function e1() {
eval $1
}
% e1 "ls ${fname}_*"
file_1 file_2 file_3
# eval は結局のところ文字列からパースするのだから、こんな書き方ができる。
function e2() {
eval "$1"
}
# この関数の実装であれば、これも動くし、
% e2 ls
file_1 file_2 file_3 other_1 other_2 other_3
# これも動く
% e2 "ls ${fname}_*"
file_1 file_2 file_3
# あーだからこうすると、
function e3() {
eval "$*"
}
# これは結局、一つ余計にコマンドを打たなきゃいけないだけのシェルだ。
% e3 ls ${fname}_*
file_1 file_2 file_3
|
| © Shin Nakamura/BasicWerk 2014 |