回答:
何がより簡単になりecho $!
ますか?1行として:
myCommand & echo $!
myprogram
素晴らしいされているだろう
&
、前の行としてa を使用してコマンドを開始する必要があります。そうでない場合、エコーは基本的に空白を返します。
command & echo $!
、このステップで実行がフリーズします:(
sh -c
およびexec
を使用して、コマンドの実行前であってもコマンドのPIDを取得できます。を開始してmyCommand
、実行を開始する前にPIDが出力されるようにするには、次を使用できます。
sh -c 'echo $$; exec myCommand'
これにより、新しいシェルが開始され、そのシェルのPIDが出力されます。次に、exec
ビルトインを使用してシェルをコマンドに置き換え、同じPIDを持つようにします。シェルがexec
ビルトインでコマンドを実行すると、シェルは実際にはそのコマンドになります。これは、それ自体の新しいコピーをフォークする一般的な動作ではなく、独自のPIDを持ち、コマンドになります。
これは、非同期実行(with &
)、ジョブ制御、またはを使用しps
た検索を含む代替手段よりもはるかに簡単であることがわかりました。これらのアプローチは問題ありませんが、使用する特別な理由がない限り(たとえば、コマンドが既に実行されている場合は、その場合、PIDを検索するか、ジョブ制御を使用するのが理にかなっています)、まずこの方法を検討することをお勧めします。(そして、私は確かにこれを達成するために複雑なスクリプトや他のプログラムを書くことを考えないでしょう)。
この回答には、この手法の例が含まれています。
使用しているシェルがBourneスタイルでありexec
、これらのセマンティクスを備えたビルトインをサポートしている場合でも、通常、この目的のためにsh -c
新しい(別個の)シェルプロセスを作成するために(または同等の)使用を避けないでください:
myCommand
後続のコマンドの実行を待機しているシェルはありません。sh -c 'echo $$; exec myCommand; foo
はfoo
、自分自身をに置き換えた後に実行しようとすることはできませんmyCommand
。これを最後のコマンドとして実行するスクリプトを書いていない限り、echo $$; exec myCommand
他のコマンドを実行しているシェルで使用することはできません。(echo $$; exec myCommand)
は構文的にはの方がいいかもしれませんsh -c 'echo $$; exec myCommand'
が、$$
inside を実行する(
)
と、サブシェル自体ではなく、親シェルのPIDが得られます。しかし、新しいコマンドのPIDになるのはサブシェルのPIDです。一部のシェルは、サブシェルのPIDを見つけるための独自の非移植メカニズムを提供します。これは、これに使用できます。特に、Bash 4では(echo $BASHPID; exec myCommand)
機能します。最後に、一部のシェルは、シェルがその後何もする必要がないことがわかっている場合、コマンドを実行するように最適化を実行することに注意してくださいexec
。実行する最後のコマンドであるときにいつでもこれを実行しようとするシェルもあれば、コマンドの前後に他のコマンドがない場合にのみ実行するシェルもあれば、まったく実行しないシェルもあります。効果は、書くのexec
を忘れて使用するだけの場合sh -c 'echo $$; myCommand'
、いくつかのシェルを備えたいくつかのシステムで正しいPIDを提供することです。そのような振る舞いに依存することはお勧めせず、代わりにいつそれが必要かを常に含めます。exec
myCommand
、bashスクリプトでいくつかの環境変数を設定する必要があります。これらexec
は、コマンドが実行されている環境に引き継がれますか?
exec
コマンドに引き継がれているようです。ただし、この方法はmyCommand
、他のプロセスを開始するときには機能しません。他のプロセスは、作業する必要があるプロセスです。私が発行したときにkill -INT <pid>
どこにpid
このように得られた、サブプロセスに到達していない信号がによって始めmyCommand
、私が実行した場合のに対し、myCommand
現在のセッションとCtrl + Cで、信号が正しく伝播します。
sh -c 'echo $$; exec /usr/local/bin/mbdyn -f "input.file" -o "/path/to/outputdir" > "command_output.txt" 2>&1 &'
pidをファイルに登録した後、bashスクリプトからexecを使用します。
例:
args p1、p2、p3で実行したい「forever.sh」という名前のスクリプトがあるとします
forever.shソースコード:
#!/bin/sh
while [ 1 -lt 2 ] ; do
logger "$0 running with parameters \"$@\""
sleep 5
done
reaper.shを作成します。
#!/bin/sh
echo $$ > /var/run/$1.pid
exec "$@"
reaper.shからforever.shを実行します。
./reaper.sh ./forever.sh p1 p2 p3 p4 &
forever.shは、5秒ごとにsyslogに行を記録するだけです。
あなたは今/var/run/forever.sh.pidにpidを持っています
cat /var/run/forever.sh.pid
5780
そしてforever.shはaokを実行しています。syslog grep:
Nov 24 16:07:17 pinkpony cia: ./forever.sh running with parameters "p1 p2 p3 p4"
プロセステーブルで確認できます。
ps axuwww|grep 'forever.sh p1' |grep -v grep
root 5780 0.0 0.0 4148 624 pts/7 S 16:07 0:00 /bin/sh ./forever.sh p1 p2 p3 p4
exec "$@"
には、の代わりに使用する必要がありますexec $*
。技術的に保存する必要があるのは、空白ではなく、IFSシェルパラメーター(デフォルトではスペース、タブ、改行)の文字の出現です。
次のようなものを使用できます。
$ myCommand ; pid=$!
または
$ myCommand && pid=$!
2つのコマンドは、;
またはを使用したジョイントにすることができます&&
。2番目の場合、pidは最初のコマンドが成功した場合にのみ設定されます。プロセスIDはから取得できます$pid
。
$!
後、&&
または参照;
することはありません。$!
非同期に起動されたプロセスに対してのみ設定されます(通常&
、一部のシェルには他のメソッドもあります)。
これはちょっとしたハック的な答えであり、ほとんどの人にはうまくいかないでしょう。また、これはセキュリティリスクが非常に大きいため、安全であり、入力がサニタイズされていると確信している場合を除き、実行しないでください。
ここで小さなCプログラムをstart
(または、必要な)と呼ばれるバイナリにコンパイルし、プログラムを次のように実行します。./start your-program-here arg0 arg1 arg2 ...
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char **argv)
{
if (argc >= 2)
{
printf("%lu\n", (long unsigned) getpid());
if (execvp(argv[1], &argv[1]) < 0)
{
perror(NULL);
return 127;
}
}
return 0;
}
要するに、これはPIDをに出力しstdout
、プログラムをプロセスにロードします。それでも同じPIDが必要です。
stdout
は不明な理由で、この例では記録されていないようですRESULT="$(./start_and_get_pid.out echo yo)"; echo "$RESULT"
sleep 10 & PID_IS=$!; echo $PID_IS