bash -cを使ったコマンドとしての変数

bash -cを使ったコマンドとしての変数

誰かが作成した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/directorycd ""現在のディレクトリは変更されません)、印刷します/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"

しかし、以下を使用するevalsh

    var='echo "this is var"' ; eval "$var" ; sh -c "$var"

出力:

this is var
this is var

evalorを使用すると、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であるため、これを使用しています。これは、新しいプロセスを開始する必要がないことを意味します。テストのために交換しましたが、費用が少し聞きました。しかし、実行ファイルを実行する方が高速です。ここでの主な違いは、新しいシェルを起動するのではなく(現在のシェルでコマンドを実行する)、新しいシェルを起動してから新しいシェルでコマンドを実行することです。新しいシェルを起動するには時間がかかります。echobash/bin/echoechobash -c1.28sevalevalbash -cbash -ceval

関連情報