web-dev-qa-db-ja.com

bashの「eval」コマンドとは何ですか?

evalコマンドで何ができますか?なぜそれが役立つのですか?それはbashの組み込み関数のようなものですか? manページはありません。

210
LanceBaynes

evalはPOSIXの一部です。シェルに組み込み可能なインターフェース。

「POSIXプログラマーズマニュアル」に記載: http://www.unix.com/man-page/posix/1posix/eval/

eval - construct command by concatenating arguments

引数を取り、そのコマンドを作成します。これはシェルによって実行されます。これはマンページの例です:

1) foo=10 x=foo
2) y='$'$x
3) echo $y
4) $foo
5) eval y='$'$x
6) echo $y
7) 10
  1. 最初の行では、$fooを値'10'で定義し、$xを値'foo'で定義します。
  2. 次に、$yという文字列で構成される'$foo'を定義します。ドル記号は'$'でエスケープする必要があります。
  3. 結果を確認するには、echo $y
  4. 結果は文字列'$foo'になります
  5. 次に、evalを使用して割り当てを繰り返します。最初に$xを文字列'foo'に評価します。これで、y=$fooと評価されるy=10というステートメントができました。
  6. echo $yの結果は、値'10'になりました。

これは、多くの言語で一般的な機能です。 PerlおよびJavaScript。その他の例については、perldoc evalをご覧ください。 http://perldoc.Perl.org/functions/eval.html

150
echox

はい、evalはbashの内部コマンドなので、bashのマニュアルページで説明しています。

eval [arg ...]
    The  args  are read and concatenated together into a single com-
    mand.  This command is then read and executed by the Shell,  and
    its  exit status is returned as the value of eval.  If there are
    no args, or only null arguments, eval returns 0.

通常、これは Command Substitution と組み合わせて使用​​されます。明示的なevalがない場合、シェルはexecuteではなく、コマンド置換の結果をexecuteしようとします。

VAR=value; echo $VARに相当するものをコーディングしたいとします。シェルがecho VAR=valueの書き込みを処理する方法の違いに注意してください。

  1. andcoz@...:~> $( echo VAR=value )
    bash: VAR=value: command not found
    andcoz@...:~> echo $VAR
    <empty line>
    

    シェルは、echoおよびVAR=valueを2つの別々のコマンドとして実行しようとします。 2番目の文字列に関するエラーをスローします。割り当ては無効のままです。

  2. andcoz@...:~> eval $( echo VAR=value )
    andcoz@...:~> echo $VAR
    value
    
    シェルは2つの文字列echoVAR=valueをマージ(連結)し、適切なルールに従ってこの単一のユニットを解析して実行します。

最後に重要なことですが、evalは非常に危険なコマンドになる可能性があります。 evalコマンドへの入力は、セキュリティ上の問題を回避するために注意深くチェックする必要があります。

65
andcoz

evalには、独立した外部コマンドではなく、組み込みのシェル(シェルの内部でのみ認識されるコマンド(bash)を意味する)であるため、manページはありません。 bash manページの関連部分には、次のように記載されています。

eval [arg ...]
    The args are read and concatenated together into a single command.  
    This command is then  read  and executed by the Shell, and its exit 
    status is returned as the value of eval.  If there are no args, or only 
    null arguments, eval returns 0

さらに、出力はhelp evalは:

eval: eval [arg ...]
    Execute arguments as a Shell command.

    Combine ARGs into a single string, use the result as input to the Shell,
    and execute the resulting commands.

    Exit Status:
    Returns exit status of command or success if command is null.

evalは強力なコマンドであり、それを使用する場合は、それに伴う可能性のある セキュリティリスク を回避するように非常に注意する必要があります。

19
jw013

Evalステートメントは、evalの引数をコマンドとして受け取り、コマンドラインを介して実行するようにシェルに指示します。以下のような状況で役立ちます。

スクリプトでコマンドを変数に定義していて、後でそのコマンドを使用する場合は、evalを使用する必要があります。

/home/user1 > a="ls | more"
/home/user1 > $a
bash: command not found: ls | more
/home/user1 > # Above command didn't work as ls tried to list file with name pipe (|) and more. But these files are not there
/home/user1 > eval $a
file.txt
mailids
remote_cmd.sh
sample.txt
tmp
/home/user1 >
18
Nikhil Gupta

Evalとは何ですか?

evalは、通常組み込みとして実装されるシェルコマンドです。

POSIXでは、エントリ "2.14。特別な組み込みユーティリティ" のエントリ "eval" としてリストされています。
ビルトインの意味は:

「組み込み」という用語は、シェルがユーティリティを直接実行でき、ユーティリティを検索する必要がないことを意味します。

それは何をするためのものか?

簡単に言うと、入力行を解析するtwiceようにします。

それはどのように行うのですか?

シェルには、行を「処理」するための一連のステップがあります。あなたは この画像を見る を見て、左側のステップ1に戻って、evalが唯一の行であることを理解します。 POSIXの説明 から:

2.1シェルの紹介

  1. シェルは入力を読み取ります....
  2. シェルは入力をトークンに分解します:単語と演算子
  3. シェルは入力を解析して、単純なコマンドと複合コマンドを作成します。
  4. シェルはさまざまな拡張を(個別に)実行します...
  5. シェルはリダイレクトを実行し、リダイレクト演算子とそのオペランドをパラメーターリストから削除します。
  6. シェルは、関数、組み込み、実行可能ファイル、またはスクリプトを実行します...
  7. シェルはオプションで、コマンドが完了するまで待機し、終了ステータスを収集します。

ステップ6で組み込みが実行されます。
ステップ6で、evalは処理されたラインをステップ1に送り返します。
これは、実行シーケンスが戻る唯一の条件です。

それが私が言う理由です:evalで入力行が解析されますtwice

2回の解析の影響。

最初。

そして理解すべき最も重要な効果。行が上記の7つのシェル手順の対象となる最初の結果は、quotingです。ステップ4(拡張)内には すべての拡張を実行する一連のステップ もあり、その最後は引用削除

見積もりの​​削除は常に最後に実行されるものとします。

したがって、常に、1つのレベルの引用が削除されます。

二番目。

その最初の効果の結果として、行の追加/異なる部分がシェルの解析と他のすべてのステップにさらされます。

例。

間接。

これにより、間接展開を実行できます。

a=b b=c    ;    eval echo \$$a            ### shall produce "c"

どうして?最初のループでは、最初の$が引用されているためです。
そのため、シェルによる展開では無視されます。
aという名前の次の$は、「b」を生成するために展開されます。
その後、1レベルの引用が削除され、最初の$が引用解除されます。
最初のループの終わり。

次に、2番目のループで、文字列$bがシェルによって読み取られます。
次に「c」に拡張されます
そしてechoへの引数として与えられます。

Evalが最初のループで生成する(再評価される)ものを「見る」には、echoを使用します。または、引数を明確に示すコマンド/スクリプト/プログラム:

$ a=b b=c
$ eval echo \$$a;
c

Evalをechoに置き換えて、何が起こっているかを「確認」します。

$ echo echo \$$a
echo $b

また、行のすべての「部分」を表示することもできます。

$ printf '<%s> ' echo \$$a
<echo> <$b>

この例では、これは1つのエコーと1つの変数だけですが、より複雑なケースの評価に役立つように覚えておいてください。

修正。

上記のコードに誤りがありますが、わかりますか?.
簡単:いくつかの引用符が抜けています。

どうやって?あなたが尋ねるかもしれません。簡単です。変数(コードではありません)を変更します。

$ a=b b="hi     jk"
$ eval echo \$$a
hi jk

不足しているスペースを確認しますか?
これは、$b内の値がシェルによって分割されたためです。

それでも納得できない場合は、これを試してください:

$ a=b b="hi  *  jk"
$ eval echo \$$a              ### warning this will expand to the list  
                              ### of all files in the present directory.

どうして?

引用符がありません。正しく機能させるには(内部"$a"および外部\"の引用符を追加)。
これを試してください(完全に安全です):

$ a=b b="hi      *       jk"
$ eval echo \" \$"$a" \"
hi      *       jk

マニュアルについて:

マニュアルページはありません。

いいえ、このための独立したmanページはありません。 man -f evalまたはapropos evalでマニュアルを検索しても、エントリは表示されません。

man bashに含まれています。組み込みのものと同様です。
「Shell BUILTIN COMMANDS」を検索し、次に「eval」を検索します。

ヘルプを取得する簡単な方法は次のとおりです。bashでは、help evalを実行して、組み込みのヘルプを表示できます。

Evalがevilと呼ばれるのはなぜですか?

これは、テキストをコードに動的にバインドするためです。

つまり、引数のリスト(および/またはそのような引数の展開)を実行された行に変換します。何らかの理由で攻撃者が引数を設定した場合、攻撃者のコードが実行されます。

またはもっと簡単に言えば、evalを使用すると、1つまたは複数の引数の値を定義した人に通知します。

さあ、ここに座ってコマンドラインをタイプしてください、私は自分の力でそれを実行します。

危ないですか?それは誰にとっても明確であるべきです。

Evalの安全規則は次のとおりです。
あなたが値を与えた変数に対してのみevalを実行します。

詳細はこちら をお読みください。

12
user79743

evalは、シェルだけでなく、ほとんどのインタプリタ言語(TCLpythonRuby...)の機能です。コードを動的に評価するために使用されます。

シェルでは、それはシェル組み込みコマンドとして実装されます。

基本的に、evalは文字列を引数として取り、その中のコードを評価/解釈します。シェルでは、evalは複数の引数を取ることができますが、evalはそれらを連結して評価する文字列を形成します。

コードを動的に作成して実行できるため、非常に強力です。これは、Cなどのコンパイル済み言語では実行できないことです。

お気に入り:

varname=$1 varvalue=$2
eval "$varname=\$varvalue" # evaluate a string like "foo=$varvalue"
                           # which in Bourne-like Shell language
                           # is a variable assignment.

ただし、evalに渡されるものの動的な(外部で提供される)部分をサニタイズすることが重要であり、シェルコードとして解釈されるため、これも危険です。

たとえば、上記の場合、$1evil-command; varの場合、evalは最終的にevil-command; var=$varvalueシェルコードを評価し、そのevil-commandを実行します。

evalの悪さは、しばしば誇張されすぎます。

はい、危険ですが、少なくとも危険であることはわかっています。

他の多くのコマンドは、(シェルに応じて)[別名testexportprintfのように、サニタイズされていない場合、引数でシェルコードを評価します、GNU sedawk、そしてもちろんsh/bash/Perlとすべて通訳...

例(ここでは、unameevil-commandとして使用し、$aを外部で提供される非サニタイズ済みデータとして使用しています):

$ a='$(uname>&2)' sh -c 'eval "echo $a"'
Linux

$ a='x[0$(uname>&2)]' mksh -c 'export "$a=$b"'
Linux
$ a='x[0$(uname>&2)]' ksh93 -c 'printf "%d\n" "$a"'
Linux
0
$ a='x[0$(uname>&2)]' ksh93 -c '[ "$a" -gt 0 ]'
Linux
$ a=$'bar/g;e uname>&2\n;s//'; echo foo | sed "s/foo/$a/g"
Linux
bar
$ a='";system("uname");"'; awk "BEGIN{print \"$a\"}"

Linux
$ a=';uname'; sh -c "echo $a"

Linux

これらのsedexport...コマンドは、eval "$var"$varの内容をシェルコードとして評価することは明らかであるため、より危険であると見なされる可能性があります。 sed "s/foo/$var/"またはexport "$var=value"または[ "$var" -gt 0 ]ではそれほど明確ではありません。危険性は同じですが、他のコマンドでは隠されています。

11

この例は、いくつかの光を当てるかもしれません:

#!/bin/bash
VAR1=25
VAR2='$VAR1'
VAR3='$VAR2'
echo "$VAR3"
eval echo "$VAR3"
eval eval echo "$VAR3"

上記のスクリプトの出力:

$VAR2
$VAR1
25
5
LoMaPh