
exec
どちらかを分岐しないでください。env
次の例を参照してください。
docker run --rm -it ubuntu:18.04 sh -c 'exec sleep 1 & ps -Ho pid,ppid,cmd'
PID PPID CMD
1 0 sh -c exec sleep 1 & ps -Ho pid,ppid,cmd
7 1 sleep 1
8 1 ps -Ho pid,ppid,cmd
docker run --rm -it ubuntu:18.04 sh -c 'env sleep 1 & ps -Ho pid,ppid,cmd'
PID PPID CMD
1 0 sh -c env sleep 1 & ps -Ho pid,ppid,cmd
7 1 sleep 1
8 1 ps -Ho pid,ppid,cmd
質問
多くの人が使用しているのを見ますが、同じではないので必要exec env ...
ないと思います。exec
env
exec
exec env
代わりに使用する必要があるユースケースはありますかenv
?
答え1
env
(おそらく)自分を分岐せずに実行するプログラムに自分自身を置き換えます。しかし、これは親シェルを分岐するか、env
単にenv
。
たとえば、次の2つを比較します。
$ bash -c 'env ls > /dev/null; echo hi'
hi
$ bash -c 'exec env ls > /dev/null; echo hi'
[no output]
を使用すると、exec
シェル自体が置き換えられ、次はecho
実行されません。
もちろんあなたはexec env ... &
。を使用すると、&
シェルはとにかくバックグラウンドプロセスを開始するために分岐し、分岐しない可能性があります。再びバックグラウンドジョブで単一のコマンドを実行します。少なくともBashはこの状況を最適化します。たとえば、次のようになります。
$ bash -c 'ps -Ho pid,ppid,cmd; echo x'
PID PPID CMD
11967 1545 -/bin/bash
14851 11967 bash -c ps -Ho pid,ppid,cmd; echo x
14852 14851 ps -Ho pid,ppid,cmd
x
$ bash -c 'ps -Ho pid,ppid,cmd'
PID PPID CMD
11967 1545 -/bin/bash
14853 11967 ps -Ho pid,ppid,cmd
後者が中間プロセスを表示しない場合は、そのbash
プロセスが存在するかのように動作しますexec
。 (-/bin/bash
私の対話型シェルです。)
Bashは単一のコマンドに対してのみこれを行います。複数のコマンドがある場合、シェルは最後のコマンドが終了するのを待ちます。使用する方法exec
は異なります。
$ bash -c 'echo x; ps -Ho pid,ppid,cmd'
x
PID PPID CMD
11967 1545 -/bin/bash
14929 11967 bash -c echo x; ps -Ho pid,ppid,cmd
14930 14929 ps -Ho pid,ppid,cmd
$ bash -c 'echo x; exec ps -Ho pid,ppid,cmd'
x
PID PPID CMD
11967 1545 -/bin/bash
14933 11967 ps -Ho pid,ppid,cmd
の場合、&
これは次のとおりですexec ps
。
$ bash -c 'ps -Ho pid,ppid,cmd & sleep 1'
PID PPID CMD
11967 1545 -/bin/bash
14867 11967 bash -c ps -Ho pid,ppid,cmd & sleep 1
14868 14867 ps -Ho pid,ppid,cmd
14869 14867 sleep 1
ただし、複合ブロックではバックグラウンドシェルプロセスも表示できます。
$ bash -c '{ ps -Ho pid,ppid,cmd; } & sleep 1'
PID PPID CMD
11967 1545 -/bin/bash
14877 11967 bash -c { ps -Ho pid,ppid,cmd; } & sleep 1
14878 14877 bash -c { ps -Ho pid,ppid,cmd; } & sleep 1
14880 14878 ps -Ho pid,ppid,cmd
14879 14877 sleep 1
これらの人々が何をしたかについての具体的な情報源を提供していないexec env
ので、彼らの正確な状況を知ることはできません。ただし、シェルを別のプロセスに置き換えるには、次exec env
の方法を使用できます。exec anyprogram
たとえば、次のシミュレーションの例は次のとおりです。
#!/bin/bash
. someconfigfile
if [ "$someconfig" = blah ]; then
exec env myprogram some args...
echo "failed to start" >&2
exit 1
elif
... whatever
fi
exec
シェルがメモリに無駄に残らないように、スクリプトを起動したプログラムに置き換えてください。また、スクリプトにプログラムを開始する仲介者が 1 つしかない場合、仲介者を実行するとexec
PID が同じままであるため、親 (スクリプトの親、その後はプログラムの親) が子を監視しやすくなります。