eval
コマンドで何ができますか?なぜそれが役立つのですか?それはbashの組み込み関数のようなものですか? man
ページはありません。
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
$foo
を値'10'
で定義し、$x
を値'foo'
で定義します。$y
という文字列で構成される'$foo'
を定義します。ドル記号は'$'
でエスケープする必要があります。echo $y
。'$foo'
になりますeval
を使用して割り当てを繰り返します。最初に$x
を文字列'foo'
に評価します。これで、y=$foo
と評価されるy=10
というステートメントができました。echo $y
の結果は、値'10'
になりました。これは、多くの言語で一般的な機能です。 PerlおよびJavaScript。その他の例については、perldoc evalをご覧ください。 http://perldoc.Perl.org/functions/eval.html
はい、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
の書き込みを処理する方法の違いに注意してください。
andcoz@...:~> $( echo VAR=value )
bash: VAR=value: command not found
andcoz@...:~> echo $VAR
<empty line>
シェルは、echo
およびVAR=value
を2つの別々のコマンドとして実行しようとします。 2番目の文字列に関するエラーをスローします。割り当ては無効のままです。
andcoz@...:~> eval $( echo VAR=value )
andcoz@...:~> echo $VAR
value
シェルは2つの文字列echo
とVAR=value
をマージ(連結)し、適切なルールに従ってこの単一のユニットを解析して実行します。最後に重要なことですが、eval
は非常に危険なコマンドになる可能性があります。 eval
コマンドへの入力は、セキュリティ上の問題を回避するために注意深くチェックする必要があります。
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
は強力なコマンドであり、それを使用する場合は、それに伴う可能性のある セキュリティリスク を回避するように非常に注意する必要があります。
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 >
evalは、通常組み込みとして実装されるシェルコマンドです。
POSIXでは、エントリ "2.14。特別な組み込みユーティリティ" のエントリ "eval" としてリストされています。
ビルトインの意味は:
「組み込み」という用語は、シェルがユーティリティを直接実行でき、ユーティリティを検索する必要がないことを意味します。
簡単に言うと、入力行を解析するtwiceようにします。
シェルには、行を「処理」するための一連のステップがあります。あなたは この画像を見る を見て、左側のステップ1に戻って、evalが唯一の行であることを理解します。 POSIXの説明 から:
2.1シェルの紹介
- シェルは入力を読み取ります....
- シェルは入力をトークンに分解します:単語と演算子
- シェルは入力を解析して、単純なコマンドと複合コマンドを作成します。
- シェルはさまざまな拡張を(個別に)実行します...
- シェルはリダイレクトを実行し、リダイレクト演算子とそのオペランドをパラメーターリストから削除します。
- シェルは、関数、組み込み、実行可能ファイル、またはスクリプトを実行します...
- シェルはオプションで、コマンドが完了するまで待機し、終了ステータスを収集します。
ステップ6で組み込みが実行されます。
ステップ6で、evalは処理されたラインをステップ1に送り返します。
これは、実行シーケンスが戻る唯一の条件です。
それが私が言う理由です:evalで入力行が解析されますtwice。
そして理解すべき最も重要な効果。行が上記の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を使用すると、1つまたは複数の引数の値を定義した人に通知します。
さあ、ここに座ってコマンドラインをタイプしてください、私は自分の力でそれを実行します。
危ないですか?それは誰にとっても明確であるべきです。
Evalの安全規則は次のとおりです。
あなたが値を与えた変数に対してのみevalを実行します。
詳細はこちら をお読みください。
eval
は、シェルだけでなく、ほとんどのインタプリタ言語(TCL
、python
、Ruby
...)の機能です。コードを動的に評価するために使用されます。
シェルでは、それはシェル組み込みコマンドとして実装されます。
基本的に、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
に渡されるものの動的な(外部で提供される)部分をサニタイズすることが重要であり、シェルコードとして解釈されるため、これも危険です。
たとえば、上記の場合、$1
がevil-command; var
の場合、eval
は最終的にevil-command; var=$varvalue
シェルコードを評価し、そのevil-command
を実行します。
eval
の悪さは、しばしば誇張されすぎます。
はい、危険ですが、少なくとも危険であることはわかっています。
他の多くのコマンドは、(シェルに応じて)[
別名test
、export
、printf
のように、サニタイズされていない場合、引数でシェルコードを評価します、GNU sed
、awk
、そしてもちろんsh
/bash
/Perl
とすべて通訳...
例(ここでは、uname
をevil-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
これらのsed
、export
...コマンドは、eval "$var"
が$var
の内容をシェルコードとして評価することは明らかであるため、より危険であると見なされる可能性があります。 sed "s/foo/$var/"
またはexport "$var=value"
または[ "$var" -gt 0 ]
ではそれほど明確ではありません。危険性は同じですが、他のコマンドでは隠されています。
この例は、いくつかの光を当てるかもしれません:
#!/bin/bash
VAR1=25
VAR2='$VAR1'
VAR3='$VAR2'
echo "$VAR3"
eval echo "$VAR3"
eval eval echo "$VAR3"
上記のスクリプトの出力:
$VAR2
$VAR1
25