web-dev-qa-db-ja.com

開始したプロセスのPIDを取得する方法

プロセス(例:myCommand)を開始してそのpidを取得したい(後で終了できるようにするため)。

名前でpsとフィルターを試しましたが、名前でプロセスを区別できません

myCommand
ps ux | awk '/<myCommand>/ {print $2}' 

プロセス名は一意ではないためです。

私はプロセスを実行できます:

myCommand &

このPIDは次の方法で取得できることがわかりました。

echo $!

より簡単な解決策はありますか?

私はmyCommandを実行して、1つの行コマンドの結果としてそのPIDを取得できれば幸いです。

78
rafalmag

echo $!よりも簡単なものは何ですか? 1行として:

myCommand & echo $!
86
Jacek Konieczny

コマンドを小さなスクリプトで囲みます

#!/bin/bash
yourcommand &
echo $! >/path/to/pid.file
30
user9517

sh -cexecを使用して、コマンドのPIDをbeforebeforeでも実行できます。

myCommandを開始して、そのPIDが実行を開始する前に出力されるようにするには、以下を使用できます。

sh -c 'echo $$; exec myCommand'

使い方:

これは、新しいシェルを開始し、そのシェルのPIDを出力し、次にexecビルトインを使用して、コマンドでシェルをreplaceして、同じであることを確認しますPID。シェルがexec組み込みコマンドを実行すると、シェルは 実際にはになるそのコマンド ではなく、 それ自体の新しいコピーをフォークするより一般的な動作 よりも、独自の個別のPIDを持ち、それがコマンドになります。

これは、非同期実行(&を使用)、ジョブ制御、またはpsを使用した検索を含む代替方法よりもはるかに簡単であることがわかりました。これらのアプローチは問題ありませんが、それらを使用する特定の理由がない限り-たとえば、コマンドが既に実行されている場合は、そのPIDの検索またはジョブ制御の使用が理にかなっています-この方法を最初に検討することをお勧めします。 (そして、私はこれを達成するために複雑なスクリプトや他のプログラムを書くことを確かに考慮しませんでした)。

この回答 には、この手法の例が含まれています。


そのコマンドの一部は時々省略できますが、通常は省略できません。

使用しているシェルがボーンスタイルであり、これらのセマンティクスでexecビルトインをサポートしている場合でも、sh -c(または同等のもの)を使用して新しいseparateこの目的のためのシェルプロセス。

  • シェルがmyCommandになると、後続のコマンドの実行を待機しているシェルはなくなります。 sh -c 'echo $$; exec myCommand; fooは、fooに置き換えられた後、myCommandを実行することはできません。これを最後のコマンドとして実行するスクリプトを作成しているのでない限り、他のコマンドを実行しているシェルでecho $$; exec myCommandを使用することはできません。
  • これには サブシェル を使用できません。 (echo $$; exec myCommand)sh -c 'echo $$; exec myCommand'より構文的に優れている可能性がありますが、$$ _(内で)を実行すると、サブシェルではなく親シェルのPIDが提供されます自体。ただし、新しいコマンドのPIDになるのはサブシェルのPIDです。一部のシェルは、サブシェルのPIDを見つけるための独自の非移植可能なメカニズムを提供します。これは、これを使用できます。特に、 Bash 4 では、(echo $BASHPID; exec myCommand)は機能します。

最後に、一部のシェルは optimization を実行することに注意してください。シェルは必要ないことがわかっている場合、exec(つまり、最初にforkを忘れる)のようにコマンドを実行します。その後は何でもします。実行する最後のコマンドであるときにいつでもこれを実行しようとするシェルもあれば、コマンドの前後に他のコマンドがない場合にのみ実行するシェルもあれば、まったく実行しないシェルもあります。その効果は、execを書くのを忘れてsh -c 'echo $$; myCommand'だけを使用した場合、sometimesが正しいPIDをsomesomeシェルを備えたシステム。 そのような振る舞い に依存することはお勧めしません。代わりに、それが必要な場合は常にexecを常に含めるようにしてください。

24
Eliah Kagan

もっと簡単な解決策は知りませんが、$を使用していません!十分ですか?他の人が言うように、後で必要になる場合はいつでも他の変数に値を割り当てることができます。

補足として、psからパイプする代わりに、pgrepまたはpidofを使用できます。

7
carlpett

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は正常に実行されています。 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
5
user237419

Bashシェルでは、$!の代わりにjobs -pが組み込まれている場合があります。場合によっては、!$!が変数展開の前(または代わり)にシェルによって解釈され、予期しない結果が生じることがあります。

たとえば、これは機能しません。

((yourcommand) & echo $! >/var/run/pidfile)

これは:

((yourcommand) & jobs -p >/var/run/pidfile)
3
mustaccio

これはちょっとハックっぽい答えで、ほとんどの人にはうまくいきません。また、これは非常に大きなセキュリティリスクとなるため、安全であり、入力が無害化されていることを確信していない限り、実行しないでください。

ここで小さな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が必要です。

1
tonysdg

あなたは次のようなものを使うことができます:

$ myCommand ; pid=$!

または

$ myCommand && pid=$!

2つのコマンドは、;または&&を使用して結合できます。 2番目のケースでは、pidは最初のコマンドが成功した場合にのみ設定されます。プロセスIDは$pidから取得できます。

1
Khaled