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