書式
eval [COMMANDS...]

概要

eval は指定された引数を
コマンドとして評価します。

1つ以上の引数が指定されたとき、
すべての引数は
スペースを使って連結されます。

実行例

以下の例では
ls コマンドを呼びます。

他のシェルと違って
fishにおいては、
コマンドそのものを
シェル変数として使えません。

それを回避するために
eval を使います。

set cmd ls
eval $cmd

訳注:上記の方法は落とし穴があります。

やはりfishにおいては
関数 を定義するべきです。

スペースを含むファイル名に注意

上記の方法には重大な欠点があります。

eval でスペースを含む
ファイル名を扱うときには、
二重でクオート・エスケープする
必要があります。

/tmp/xx ディレクトリにて
実証してみます。

スペースを含まない
ファイル名についてはOKです。

$ cd /tmp
$ mkdir xx
$ cd xx
$ touch a.txt
$ set cmd ls
$ eval $cmd
a.txt

ところが、
スペースを含むファイル名では
破綻します。

なぜなら eval は、
すべての引数をスペースで連結
するからです。

eval $cmd 'file with spaces.txt' は、
ls file whith spaces.txt
として評価されるため
うまくいきません。

$ touch 'file with spaces.txt'
$ eval $cmd 'file with spaces.txt'
ls: 'file' にアクセスできません: そのようなファイルやディレクトリはありません
ls: 'with' にアクセスできません: そのようなファイルやディレクトリはありません
ls: 'spaces.txt' にアクセスできません: そのようなファイルやディレクトリはありません

そのためには、

  • クオート内でクオートを入れるか
  • クオート内でエスケープする

必要があります。

$ ls 'file with spaces.txt'
file with spaces.txt
$ eval $cmd "'file with spaces.txt'"
file with spaces.txt
$ eval $cmd '"file with spaces.txt"'
file with spaces.txt
$ eval $cmd 'file\ with\ spaces.txt'
file with spaces.txt
$ eval $cmd "file\ with\ spaces.txt"
file with spaces.txt

結局は function
関数定義するのがベストです。

$ function cmd; ls $argv; end
$ cmd 'file with spaces.txt'
file with spaces.txt

後片付け。

$ cd
$ rm -rf /tmp/xx

最後までお読みいただき、ありがとうございました。参考になれば嬉しいです。