誰かが作成したbashスクリプトを読んでい
ました。
bash -c "$1"
変える
eval "$1"
私はevalを使用することが好ましい方法だと思い、とにかくより速くなります。本当に?
2つの間に実質的な違いはありますか? 2つの重要な違いは何ですか?
答え1
eval "$1"
現在のスクリプトでコマンドを実行します。現在のスクリプトでシェル変数の設定と使用、現在のスクリプトの環境変数の設定、現在のスクリプトで機能の設定と使用、および現在のスクリプトの現在のディレクトリ、umask、制限、およびその他のプロパティを設定できます。bash -c "$1"
環境変数、ファイル記述子、およびその他のプロセス環境を継承しますが(変更を再度渡しません)、まったく別のスクリプトでコマンドを実行しますが、内部シェル設定(シェル変数、関数、オプション、トラップなど)は継承しません。 。
サブシェルでコマンドを実行する別の方法があります(eval "$1")
。呼び出しスクリプトからすべてを継承しますが、変更を再度渡しません。
たとえば、変数がdir
エクスポートされず、次のようになり$1
ますcd "$foo"; ls
。
cd /starting/directory; foo=/somewhere/else; eval "$1"; pwd
内容を一覧表示し/somewhere/else
て印刷します/somewhere/else
。cd /starting/directory; foo=/somewhere/else; (eval "$1"); pwd
内容を一覧表示し/somewhere/else
て印刷します/starting/directory
。cd /starting/directory; foo=/somewhere/else; bash -c "$1"; pwd
内容を一覧表示し/starting/directory
(cd ""
現在のディレクトリは変更されません)、印刷します/starting/directory
。
答え2
最も重要な違いは
bash -c "$1"
そして
eval "$1"
前者はサブシェルで実行されますが、後者はそうではありません。だから:
set -- 'var=something'
bash -c "$1"
echo "$var"
出力:
#there doesn't seem to be anything here
set -- 'var=something'
eval "$1"
echo "$var"
出力:
something
しかし、なぜ誰かがbash
この方法で実行可能ファイルを使用するのかわかりません。呼び出す必要がある場合は、組み込みのPOSIXを使用してくださいsh
。または(subshell eval)
環境を保護するには。
.dot
個人的にはシェルを好む。
printf 'var=something%d ; echo "$var"\n' `seq 1 5` | . /dev/fd/0
出力
something1
something2
something3
something4
something5
しかし、本当に必要ですか?
実際にこれらの1つを使用する唯一の理由は、変数が実際に別の変数を割り当てるか評価するか、またはトークン化が出力にとって重要な場合です。
たとえば、
var='echo this is var' ; $var
出力:
this is var
これはうまくいきますが、echo
パラメータの数を気にしないからです。
var='echo "this is var"' ; $var
出力:
"this is var"
願いより?シェル拡張の結果が$var
評価されないため、二重引用符が表示されますquote-removal
。
var='printf %s\\n "this is var"' ; $var
出力:
"this
is
var"
しかし、以下を使用するeval
かsh
:
var='echo "this is var"' ; eval "$var" ; sh -c "$var"
出力:
this is var
this is var
eval
orを使用すると、sh
シェルは拡張結果に対して2番目の転送を実行し、それを潜在的なコマンドとして評価するため、引用符が異なります。次のようにすることもできます。
. <<VAR /dev/fd/0
${var:=echo "this is var"}
#END
VAR
出力
this is var
答え3
私は簡単なテストをしました:
time bash -c 'for i in {1..10000}; do bash -c "/bin/echo hi"; done'
time bash -c 'for i in {1..10000}; eval "/bin/echo hi"; done'
(はい、わかりました。bash -cを使用してループを実行しましたが、違いはありません。)
結果:
eval : 1.17s
bash -c : 7.15s
だからeval
より速いです。マニュアルページからeval
:
evalユーティリティは引数を一緒に連結し、各引数を文字で区切ってコマンドを設定する必要があります。生成されたコマンドはシェルから読み取って実行する必要があります。
bash -c
もちろん、bashシェルからコマンドを実行してください。注:私はこれが組み込みのシェル/bin/echo
であるため、これを使用しています。これは、新しいプロセスを開始する必要がないことを意味します。テストのために交換しましたが、費用が少し聞きました。しかし、実行ファイルを実行する方が高速です。ここでの主な違いは、新しいシェルを起動するのではなく(現在のシェルでコマンドを実行する)、新しいシェルを起動してから新しいシェルでコマンドを実行することです。新しいシェルを起動するには時間がかかります。echo
bash
/bin/echo
echo
bash -c
1.28s
eval
eval
bash -c
bash -c
eval