eval
どちらexec
もコマンドを実行するbash(1)コマンドに組み込まれています。
また、exec
いくつかのオプションがありますが、それが唯一の違いですか?彼らの背景はどうなりますか?
答え1
eval
exec
全く違う獣です。 (両方ともコマンドを実行することを除いて、シェルで実行されるすべての操作も同じです。)
$ help exec
exec: exec [-cl] [-a name] [command [arguments ...]] [redirection ...]
Replace the shell with the given command.
別のプロセスを実行するのではなく、現在のシェルがコマンドに置き換えられることを除いて、exec cmd
runとまったく同じことを行います。cmd
内部的にsayを実行すると、子プロセスが作成され、/bin/ls
子プロセスで実行されます。一方、それはfork()
exec()
/bin/ls
exec /bin/ls
いいえフォークですが、殻だけを交換するだけです。
比較する:
$ bash -c 'echo $$ ; ls -l /proc/self ; echo foo'
7218
lrwxrwxrwx 1 root root 0 Jun 30 16:49 /proc/self -> 7219
foo
そして
$ bash -c 'echo $$ ; exec ls -l /proc/self ; echo foo'
7217
lrwxrwxrwx 1 root root 0 Jun 30 16:49 /proc/self -> 7217
echo $$
私が起動したシェルのPIDを印刷すると、リストに/proc/self
私たちが実行したシェルのPIDが表示されます。ls
通常、プロセスIDは異なりますが、exec
シェルとls
同じプロセスIDを持ちます。また、exec
シェルが交換されたため、次のコマンドは実行されません。
一方:
$ help eval
eval: eval [arg ...]
Execute arguments as a shell command.
eval
引数は現在のシェルでコマンドとして実行されます。つまり、eval foo bar
just と同じですfoo bar
。ただし、変数は実行前に拡張されるため、シェル変数に格納されているコマンドを実行できます。
$ unset bar
$ cmd="bar=foo"
$ eval "$cmd"
$ echo "$bar"
foo
そうだろういいえこの変数が現在のシェルに設定されるように子プロセスを作成します。 (eval /bin/ls
もちろん、サブプロセスは既存のプロセスと同様に作成されます/bin/ls
。)
あるいは、シェルコマンドを出力するコマンドを持つこともできます。 Runningはバックグラウンドでエージェントを起動し、現在のシェルで設定し、サブプロセス(実行するコマンド)ssh-agent
で使用できる複数の変数割り当てを出力します。ssh
したがって、ssh-agent
次から始めてください。
eval $(ssh-agent)
そして、現在のシェルは他のコマンドによって継承された変数を取得します。
もちろん、変数にcmd
そのような内容が含まれている場合は、rm -rf $HOME
実行eval "$cmd"
したくありません。文字列内のコマンド置換などまで処理されるので、しなければならない本物eval
使用前に入力内容が安全であることを確認してください。
誤ってeval
コードとデータが誤って混在するのを防ぐことがよくあります。
答え2
exec
新しいプロセスは作成されません。それ変える新しいコマンドを使用する現在のプロセスです。コマンドラインでこれを行うと、シェルセッションが効果的に終了します(ログアウトしたり、ターミナルウィンドウを閉じたりすることもできます)。
例えば
ksh% bash
bash-4.2$ exec /bin/echo hello
hello
ksh%
ここにありますksh
(私の一般的な殻)。私は始めてbash
からbash exec /bin/echo
Iで始めました。プロセスがに置き換えられたksh
ため、後で返されたことがわかります。bash
/bin/echo
答え3
長い話を短く
exec
コマンドが指定されていない場合は、現在のシェルプロセスを新しいシェルプロセスに置き換えて、ストリームリダイレクト/ファイル記述子を処理します。eval
文字列をコマンドとして評価するために使用されます。どちらも実行時に既知のパラメータを使用してコマンドを作成および実行するために使用できますが、コマンドの実行に加えて、exec
現在のシェルのプロセスも置き換えます。
組み込み実行
通事論:
exec [-cl] [-a name] [command [arguments]]
マニュアルによると、この組み込みコマンドが指定されているかどうか
...ケースを交換してください。新しいプロセスは作成されません。これらのパラメーターはコマンドのパラメーターになります。
つまり、PID 1234で実行し、そのシェルで実行しbash
たい場合、コマンドはPID 1234を持ち、シェルプロセスを置き換えます。exec top -u root
top
これの用途は何ですか?ラッパースクリプトということから。これらのスクリプトは、パラメータセットを構築するか、環境に渡す変数を決定し、指定されたコマンドでexec
自分自身を置き換え、ラッパースクリプトがプロセスで構築したのと同じパラメータを提供します。
マニュアルには次のように記載されています。
コマンドを指定しないと、すべてのリダイレクトが現在のシェルに適用されます。
これにより、現在のシェルの出力ストリームにあるすべてのコンテンツをファイルにリダイレクトできます。これはコマンドを表示したくありませんが、表示のみがstdout
必要な場合は、ロギングまたはフィルタリングの目的に役立ちますstderr
。たとえば、次のようになります。
bash-4.3$ exec 3>&1
bash-4.3$ exec > test_redirect.txt
bash-4.3$ date
bash-4.3$ echo "HELLO WORLD"
bash-4.3$ exec >&3
bash-4.3$ cat test_redirect.txt
2017年 05月 20日 星期六 05:01:51 MDT
HELLO WORLD
この動作は非常に便利です。ログインシェルスクリプト、ストリームを別のファイルにリダイレクトするか、プロセス、他人楽しいものファイル記述子と共に。
少なくともbash
バージョン4.3のソースコードレベルでは、組み込み関数がexec
ありますbuiltins/exec.def
。これは受け取ったコマンドを解析し、その内容がある場合はファイルshell_execve()
で定義された関数に渡します。execute_cmd.c
簡単に言えば、Cプログラミング言語には、基本的に次のためのラッパー関数である一連のexec
コマンドがあります。shell_execve()
execve
/* Call execve (), handling interpreting shell scripts, and handling
exec failures. */
int
shell_execve (command, args, env)
char *command;
char **args, **env;
{
評価内蔵
bash 4.3のマニュアルには次のように記載されています(強調項目が追加されています)。
argsを読み込み、一緒に接続してコマンドを形成します。その後、コマンドを読んで シェルによって実行される、終了ステータスが eval 値として返されます。
プロセスの交換は発生しません。関数をexec
シミュレートする目的とは異なり、組み込み関数は、ユーザーがコマンドラインに引数を入力するかのように引数を「評価」するためにのみ使用されます。このようにして新しいプロセスが作成されます。execve()
eval
これはどこで役に立ちますか? Gilesが指摘したようにこの回答では、 "... evalは一般的に使用されていません。一部のシェルでは、実行時まで名前がわからない変数の値を取得することが最も一般的です。"個人的には、ユーザーが現在使用している特定のワークスペースに基づいてコマンドを実行/評価する必要があるUbuntuのいくつかのスクリプトでこれを使用しました。
ソースコードレベルでは、解析されbuiltins/eval.def
た入力文字列を定義してevalstring()
関数に渡します。
何よりも、次のことがeval
できます。変数の割り当て現在、シェル実行環境を維持していますが、exec
次のことはできません。
$ eval x=42
$ echo $x
42
$ exec x=42
bash: exec: x=42: not found
答え4
評価する
これらのタスクは次のとおりです。
$ echo hi
hi
$ eval "echo hi"
hi
$ exec echo hi
hi
しかし、次はそうではありません。
$ exec "echo hi"
bash: exec: echo hi: not found
$ "echo hi"
bash: echo hi: command not found
画像交換処理
exec
この例は、呼び出しプロセスのイメージを置き換える方法を示しています。
# Get PID of current shell
sh$ echo $$
1234
# Enter a subshell with PID 5678
sh$ sh
# Check PID of subshell
sh-subshell$ echo $$
5678
# Run exec
sh-subshell$ exec echo $$
5678
# We are back in our original shell!
sh$ echo $$
1234
exec echo $$
サブシェルのPIDを使用して実行されることに注意してください。また、完了すると元のシェルに戻りますsh$
。
一方eval
、いいえプロセスイメージを交換します。代わりに、シェル自体内で通常指定されたコマンドを実行します。 (もちろん、プロセス生成が必要なコマンドを実行する場合…そうなります!)
sh$ echo $$
1234
sh$ sh
sh-subshell$ echo $$
5678
sh-subshell$ eval echo $$
5678
# We are still in the subshell!
sh-subshell$ echo $$
5678