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


176

このevalコマンドで何ができますか?なぜ便利なのですか?それはbashの組み込み関数の一種ですか?そのためのmanページはありません。


28
コマンドのtype commandタイプを知るために使用します。(この場合)type eval
rozcietrzewiacz

9
「評価は、シェルの組み込みである」
ヌーノラファエル・フィゲイレド

3
help evalあなたのシェルから「男」ページを取得する
M-RIC

evalはbash組み込みであり、bashのマニュアルページに記載されています。したがって、「man bash」と入力して、evalの適切なセクションを検索します。これは、他のbash-builtinにも適用されます。
ダークタンハウザー

回答:


132

evalPOSIXの一部です。シェルの組み込みが可能なインターフェイス。

「POSIX Programmer's Manual」に記載されています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、文字列で構成されるdefineを定義します'$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


4
シェル用語でevalは、は組み込み関数であり、関数ではありません。実際には、組み込み関数は、言語内定義を持たない関数のように動作しますが、完全ではありません(呼び出される関数を定義するほどひねられている場合に明らかになりますeval)。
ジル

thx、それを修正:-)
echox

4
evalとbackticks `の違いは何ですか?
JohnyTex

5
バックティックは、別のシェル全体を実行するための省略形です。つまり、スクリプト内で別の子bash / shプロセスが実行されます。
アーロンR.

echo $ y(ステージ3)が$ fooの代わりにfoo(10)を返すのはなぜですか?(つまり、文字列$ + fooの値ではなくfooの値のみ)?
JohnDoea 16

60

はい、evalbashの内部コマンドなので、bashmanページで説明されています。

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.

通常、コマンド置換と組み合わせて使用​​されます。明示的に指定しないevalと、シェルはコマンド置換の結果を評価するのではなく、実行しようとします。

と同等のコードを作成するとしVAR=value; echo $VARます。シェルが以下の記述を処理する方法の違いに注意してくださいecho VAR=value

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

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

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

最後にevalなりましたが、非常に危険なコマンドになる可能性があります。evalセキュリティの問題を回避するために、コマンドへの入力は慎重に確認する必要があります。


18

eval別個の外部コマンドではなく、シェル組み込みコマンドであるため、manページはありません。これは、シェルの内部コマンドであり、シェルのみが知っているコマンドbashです()。bashマニュアルページの関連部分には次のように書かれています。

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


16

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 >

3
あなたの例の4行目のコメントは間違っています:「bashは次のコマンドを見つけようとしたため、上記のコマンドは動作しませんでしたls | more。つまり、スペースとパイプ記号を含む9文字。
CFI

彼が報告したのとまったく同じ動作をします。bash --version == GNU bash、バージョン3.2.57(1)-release(x86_64-apple-darwin18)
Alexander Bird

10

evalとは何ですか?

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

POSIXでは、エントリ"eval"の "2.14。Special Built-In Utilities"の一部としてリストされています。 組み込みの意味は次のとおりです。

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

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

簡単に言うと、入力行を2回解析ます。

それはどうやって?

シェルには、行を「処理」するために従う一連のステップがあります。あなたは可能性があり、この画像を見てとevalは左側に、ステップ1に戻って、上がるだけの行であることを認識しています。POSIXの説明から:

2.1シェルの紹介

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

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

それが私が言う理由です:evalでは入力行が2回解析されます。

2回の解析の効果。

最初。

そして、理解する最も重要な効果。ある行が上記の7つのシェルステップの対象となる最初の結果の1つは、引用です。ステップ4(拡張)の中には、すべての拡張を実行するための一連のステップあります。最後はQuote Removalです:

引用の削除は常に最後に実行されるものとします。

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

第二に。

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

例。

間接。

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

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

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

次に、2番目のループで$b、シェルが文字列を読み取ります。
次に「c」に展開し
、の引数として指定しechoます。

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

$ 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 -f evalまたはapropos evalエントリを表示しないマニュアルの検索。

内部に含まれていman bashます。すべてのビルトインです。
「SHELL BUILTIN COMMANDS」を検索してから、「eval」を検索します。

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

evalはなぜ悪と呼ばれるのですか?

テキストをコードに動的にバインドしているためです。

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

またはさらに簡単に、evalを使用すると、1つまたは複数の引数の値を定義した人に通知することができます。

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

それは危険ですか?それがすべてであることを明確にする必要があります。

評価のための安全規則は次のようになります
だけ先の変数にはevalを実行しますが、それは価値です与えています。

詳細はこちらご覧ください


10

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; varevalエンドアップでしょう評価evil-command; var=$varvalueシェルコードを、その後、それを実行evil-command

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

OK、それは危険ですが、少なくとも私たちはそれが危険であることを知っています。

他のコマンドの多くは、サニタイズされていない場合、(シェルによって異なります)のように、その引数にシェルコードを評価します[別名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/"or export "$var=value"またはor ではそれほど明白ではないから[ "$var" -gt 0 ]です。危険性は同じですが、それらの他のコマンドでは隠されています。


@BinaryZebra は、変数に含まれる文字列が渡されるのとsed同じようにeval、両方の場合、その文字列の内容は最終的にシェルコードとして評価されるため、sedと同じくらい危険evalです。(unameはまだ実行されていない)sedを含む文字列が渡さunamesed、unameコマンドが呼び出されると、unameコマンドが実行されます。evalが好きです。ではsed 's/foo/$a/g'、サニタイズされていないデータをsedに渡していないので、ここでは説明していません。
ステファンシャゼル

2

この例はいくらか光を放つかもしれません:

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

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

$VAR2
$VAR1
25

あなたの貢献に感謝しますが、それらは面白いのですが、の使用例(少し異なる)のリストをコンパイルすることにはあまり興味がありませんevaleval既存の答えではカバーされていない機能の基本的で重要な側面があると思いますか?その場合、それを説明し、例を使用して説明を説明します。コメントで返信しないでください。 回答を編集して、より明確で完全なものにします。
スコット
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.