web-dev-qa-db-ja.com

元のプロセスの子ではない新しいプロセスを起動するにはどうすればよいですか?

(OSX 10.7)使用するアプリケーションでは、アプリケーション内で特定のアクティビティが発生したときに呼び出されるスクリプトを割り当てることができます。私はbashスクリプトを割り当て、それが呼び出されています。問題は、いくつかのコマンドを実行し、30秒待ってから、さらにいくつかのコマンドを実行することです。 bashスクリプトで「sleep 30」を実行すると、スクリプトが完了するのを待つ間、アプリケーション全体がその30秒間フリーズします。

30秒の待機(および2番目のコマンドセット)を別のスクリプトに入れて "./secondScript&"を呼び出してみましたが、アプリケーションは30秒間そこにとどまり、何もしません。アプリケーションはスクリプトおよびすべての子プロセスが終了するのを待っていると思います。

メインスクリプト内から2番目のスクリプトを呼び出すためにこれらのバリエーションを試しましたが、すべて同じ問題があります。

  • Nohup ./secondScript&
  • ((./secondScript&)&)
  • (./secondScript&)
  • Nohupスクリプト-q/dev/null secondScript&

アプリケーションを変更して、スクリプトを起動し、完了するまで待つように指示することはできません。

新しいプロセスが現在のプロセスの子にならないように、プロセスを起動するには(スクリプトプロセスでプロセスを使用する方がよいでしょう)。

ありがとう、クリス

pS私は "disown"コマンドを試しましたが、それも役に立ちませんでした。私のメインスクリプトは次のようになります。

[initial commands]
echo Launching second script
./secondScript &
echo Looking for jobs
jobs
echo Sleeping for 1 second
sleep 1
echo Calling disown
disown
echo Looking again for jobs
jobs
echo Main script complete

そして私が出力のために得るものはこれです:

Launching second script
Looking for jobs
[1]+ Running ./secondScript &
Sleeping for 1 second
Calling disown
Looking again for jobs
Main script complete

この時点で、呼び出し元のアプリケーションは45秒間待機し、secondScriptが終了するのを待ちます。

p.p.s

メインスクリプトの上部で「ps」を実行した場合、返されるのは、別のターミナルウィンドウで開いた対話型bashセッションのプロセスIDだけです。

$ Shellの値は/ bin/bashです

「ps -p $$」を実行すると、正しく通知されます

PID   TTY TIME    CMD
26884 ??  0:00.00 mainScript

「lsof -p $$」を実行すると、あらゆる種類の結果が得られます(関連性がないと想定して、ここにすべての列を貼り付けていませんでした)。

FD   TYPE   NAME
cwd  DIR    /private/tmp/blahblahblah
txt  REG    /bin/bash
txt  REG    /usr/lib/dyld
txt  REG    /private/var/db/dyld/dyld_shared_cache_x86_64
0    PIPE   
1    PIPE   -> 0xffff8041ea2d10
2    PIPE   -> 0xffff 8017d21cb
3r   DIR    /private/tmp/blahblah
4r   REG    /Volumes/DATA/blahblah
255r REG    /Volumes/DATA/blahblah
23
Betty Crokker

Unixでこれを行う一般的な方法は、ダブルフォークです。 bashでは、これは

( sleep 30 & )

(..)は子プロセスを作成し、&は孫プロセスを作成します。子プロセスが終了すると、孫プロセスはinitによって継承されます。


これが機能しない場合、アプリケーションは子プロセスを待機していません。

それが待っているかもしれない他のものは、セッションと開いているロックファイルを含みます:

新しいセッションを作成するために、Linuxにはsetsidがあります。 OS Xでは、scriptを使用してそれを実行できる場合があります。これにより、偶然にも新しいセッションが作成されます。

# Linux:
setsid sleep 30

# OS X:
Nohup script -q -c 'sleep 30' /dev/null &

継承されたファイル記述子のリストを見つけるには、lsof -p yourpidを使用できます。これにより、次のような出力が得られます。

sleep   22479 user    0u   CHR 136,32      0t0       35 /dev/pts/32
sleep   22479 user    1u   CHR 136,32      0t0       35 /dev/pts/32
sleep   22479 user    2u   CHR 136,32      0t0       35 /dev/pts/32
sleep   22479 user    5w   REG  252,0        0  1048806 /tmp/lockfile

この場合、標準のFD 0、1、2に加えて、fd 5を開いて、親が待機している可能性のあるロックファイルを使用します。

Fd 5を閉じるには、exec 5>&-を使用できます。ロックファイル自体がstdin/stdout/stderrであると思われる場合は、Nohupを使用して、他のファイルにリダイレクトできます。

27
that other guy

別の方法は子供を捨てることです

#!/bin/bash

yourprocess &

disown

私が理解している限り、アプリケーションは通常のbashシェルを置き換えます。これは、initがこの子プロセスを処理する必要がある場合でも、プロセスが完了するのを待っているためです。 "application"が、通常initによって行われるオーファン処理をインターセプトする可能性があります。

その場合、いくつかのIPCを含む並列プロセスのみが解決策を提供できます(私の他の回答を参照))

13
thom

子プロセスが終了したかどうかを親プロセスが検出する方法に依存すると思います。私の場合(私の親プロセスはgnu makeでした)、次のようにstdoutとstderr(--- その他の人の答え にわずかに基づいています)を閉じることで成功します。

sleep 30 >&- 2>&- &

Stdinを閉じることもできます

sleep 30 <&- >&- 2>&- &

またはさらに、子プロセスを否認する(Macは対象外)

sleep 30 <&- >&- 2>&- & disown

現在、kubuntu 14.04およびMac OSXのbashでのみテストされています。

11
Joe

他のすべてが失敗した場合:

  1. 名前付きパイプを作成する

  2. 「遅い」スクリプトを開始独立アプリケーション」から、無限ループでそのタスクを実行することを確認してください。パイプからの読み取り。読み込もうとすると、読み取りがブロックされます。

  3. アプリケーションから、他のスクリプトを開始します。 「遅い」スクリプトを呼び出す必要がある場合は、パイプにデータを書き込むだけです。遅いスクリプトが開始されます独立してなので、スクリプトは「遅い」スクリプトが終了するのを待ちません。

だから、質問に答えるには:
bash-元のプロセスの子ではない新しいプロセスを起動するにはどうすればよいですか?

シンプル:起動せず、ブート中に独立したエンティティに起動させます...initのように、またはatまたはbatchを使用してオンザフライで

1
thom

ここにシェルがあります

└─bash(13882)

このようなプロセスを開始する場所:

$ (urxvt -e ssh somehost&)

プロセスツリーを取得します(この出力はpstree -p):

├─urxvt(14181)───ssh(14182)

ここで、プロセスはpid 1(私の場合はsystemd)の下に親があります。

ただし、代わりにこれを実行した場合(& is):

$ (urxvt -e ssh somehost)&

次に、プロセスはシェルの子になります。

└─bash(13882)───urxvt(14181)───ssh(14182)

どちらの場合も、シェルプロンプトがすぐに返され、上で開始したプロセスツリーを終了せずにexitを実行できます。

後者の場合、シェルが終了すると、プロセスツリーはpid 1の下で親が変更されるため、最初の例と同じになります。

├─urxvt(14181)───ssh(14182)

どちらにしても、結果はシェルよりも長く存続するプロセスツリーです。唯一の違いは、そのプロセスツリーの最初の親です。

参考までに、

  • Nohup urxvt -e ssh somehost &
  • urxvt -e ssh somehost & disown $!

どちらも、上記の2番目の例と同じプロセスツリーを提供します。

└─bash(13882)───urxvt(14181)───ssh(14182)

シェルが終了すると、プロセスツリーは以前と同様にpid 1に親が変更されます。

Nohupは、プロセスの標準出力をファイルにリダイレクトしますNohup.outしたがって、それが有用な特性である場合、それはより有用な選択である可能性があります。

それ以外の場合、上記の最初のフォームでは、完全に切り離されたプロセスツリーがすぐに得られます。

0
starfry