
eval
コマンドと一緒に使用すると、eval
コマンドのリダイレクト部分にシェルが2回適用されますか?
リダイレクトのファイル名にスペースが含まれていると仮定すると、すべてのeval
解析、シェル拡張、およびトークン化フェーズが複数回適用されると、ファイル名は2番目のトークン化フェーズで2つの単語に分割されます。
eval
次の例は、次のコマンドのリダイレクト部分にシェルが2回適用されないため、ファイル名が2つの単語に分割されないことを意味しますか?
$ filename="my file"
$ eval "cat" < "$filename"
hi
答え1
提供された例で唯一のことは、eval
リダイレクトcat
が外部で発生eval
し、ファイルがコマンドの標準入力として提供されることですeval "cat"
。
1つの変形は、単一引用符を使用してリダイレクトを含むコマンド全体を引用することです。
$ eval 'cat < "$filename"'
hi
eval
リダイレクトと変数名を含む完全な文字列が取得されるため、変数の拡張だけでなく、スペースを含む必須ファイル名参照も実行されます。これはまだ動作します。
別のオプションは、文字列に二重引用符を使用することです。
$ eval "cat < '$filename'"
hi
変数はシェルによって拡張されますが、変数内の引用符はファイル名を一緒に保持するため、まだ機能します。 (ファイル名にアポストロフィが含まれていると壊れることがあります。)
「動作しないもの」は次のとおりです。
$ eval "cat" "<" "$filename"
これはあなたの例と似ていますが、引用符を使用すると<
外部シェルはリダイレクトを実行しません。eval
その後、パラメーターを一緒に入れると、結果コマンドは次のようになります。
cat < my file
my file
これで、引用符が消えたため、期待どおりに機能しません。
答え2
どのように機能するかは、eval
実行するシェルコマンドにパラメータを一緒に設定することです。変数の後filename
引用されると、単語分割は行われません。いつこれコマンドは実行するように書かれています。
ファイル名にスペースが含まれている場合は同じことはありません。引用符なしで拡張するとエラーが発生します。例えば
filname=my\ file
echo "dude" > my\ file
eval cat < $filename
bash: $filename: ambiguous redirect
ここで行われたトークン化とcat
入力リダイレクトの間違ったファイル名を受け取り、エラーが発生したことに注意してください。
また、リダイレクトなしで使用するcat
場合、またはファイルから直接使用している場合は、eval
2つのファイルが開きます。cat
eval cat $filename
ランに切り替えます
cat my file
たとえば、指定されたファイルが現在のディレクトリにある場合は、その内容を表示し、指定されたfile
ファイルが存在しないというエラーストリームを表示します。my
filename=my\ file
echo "foo" > file
my
ファイルが存在しないようにしています。
eval cat $filename 2>&1
cat: my: No such file or directory
foo