スクリプトからバックグラウンドプロセスを開始し、スクリプトの終了時に管理します


15

スクリプトからデーモンに似たプロセスを実行および構成したいと思います。
私のシェルはCygwinでエミュレートされたzshであり、デーモンは基本的なFTPサーバーであるSFKです。

ここで重要なのは、スクリプトstartserv.shを次のように作成できることです。

#!/bin/sh
read -s -p "Enter Password: " pw
user=testuser
share=/fshare
cmd="sfk ftpserv -user=$user -pw=$pw -usedir $share=$share"
$cmd &

スクリプトを実行した後startserv.sh、プロンプトを表示せずに停止(終了?)します:

  • CTRL+ Cスクリプトとバックグラウンドジョブプロセスの両方を終了します。

  • 叩くEnterスクリプトは、プロセスがバックグラウンドに残って終わります。

とにかく私はのみを経由して、それを見ることができpsないjobs私は、プロセスを閉じたいとき、そう、私は残忍送信する必要がありkill -9、私は賛成で避けたいのですが何かある信号、 CTRL+をC

別の方法 、スクリプト全体をバックグラウンドで実行することです。「Would be」ですがread、スクリプトがとして実行される場合、コマンドはユーザー入力を取得できませんstartserv.sh &

真のデーモンではなく、一時サーバーが必要なことに注意してください。つまり、スクリプトが終了した後、サーバープロセスをバックグラウンドで実行して、(仮想マシンゲストで)簡単なインタラクティブシェルタスクを実行する必要がありますが、シェルを生き残るためのプロセスが必要です。したがって、nohup適切ではないようです。


使用してバックグラウンドで実行中のプロセスのプロセスIDを取得bgproc="$!"後、およびcommand "$bgproc" 適切な行動を取ることを。stackoverflow.com/questions/1908610/
バレンティンバジラミ14年

PIDファイルを作成することもできます。次に、そのファイルを読んで、プロセス番号を確認し、そこから進みます。
jgr208 14年

回答:


18

叩くEnterスクリプトは、プロセスがバックグラウンドに残って終わります。

ほとんど!実際、を押すまでにスクリプトはすでに終了していますEnter。ただし、これはプロンプトを元に戻す方法です(シェル$PS1が再び出力を繰り返すため)。

打撃理由Ctrl+は、Cそれらの2がリンクされているので、それらの両方を終了です。スクリプトを実行すると、シェルはそれを実行するサブシェルを開始します。このサブシェルを終了すると、おそらくSIGHUPシグナルによってバックグラウンドプロセスが停止します。

スクリプト、バックグラウンドプロセス、サブシェルを分離する

を使用するとnohup、この小さな不便さを取り除くことができるかもしれません。

#!/bin/sh
read -s -p "Enter Password: " pw
user=testuser
share=/fshare
cmd="sfk ftpserv -user=$user -pw=$pw -usedir $share=$share"
nohup $cmd &

disown選択肢

から/bin/shに切り替えることができる場合は、同様に/bin/bash試してみることができdisownます。詳細を知るには、単に入力しますhelp disownは、bashインスタンスをするです。

disown -h $cmd &

バックグラウンドプロセスを「適切に」終了する

これで、プロセスを強制終了するときに、を使用して「Ctrl+ C」を完全に実行できますkill。残忍なものを送らないでくださいSIGKILL。代わりに、次を使用できます。

$ kill -2 [PID]
$ kill -15 [PID]

プロセスに素敵なSIGINT(2)またはSIGTERM(15)を送信します。プロセスを開始した後、PID値を印刷することもできます。

...
nohup $cmd &
echo $!

...またはさらに良いのは、スクリプトがを待つSIGINTようにし、バックグラウンドプロセスに送り返すことです(これにより、スクリプトがフォアグラウンドに保持されます)

#!/bin/sh
read -s -p "Enter Password: " pw
user=testuser
share=/fshare
cmd="sfk ftpserv -user=$user -pw=$pw -usedir $share=$share"
nohup $cmd &

# Storing the background process' PID.
bg_pid=$!

# Trapping SIGINTs so we can send them back to $bg_pid.
trap "kill -2 $bg_pid" 2

# In the meantime, wait for $bg_pid to end.
wait $bg_pid

a SIGINTで十分でない場合は、SIGTERM代わりにa (15)を使用します。

trap "kill -15 $bg_pid" 2 15

このように、スクリプトがバックグラウンドプロセスのSIGINTCtrl+ Ckill -2)またはSIGTERMwhile を受け取るとwait、それは単にシグナルを中継します。これらの信号がsfkインスタンスをwait強制終了すると、呼び出しが返され、スクリプトも終了します:)


1
+1非常に有益です。スクリプトはサブシェルで実行されるため、スクリプトからスクリプトの親シェルのジョブテーブルにアクセスする可能性はありますか?これはjobs、スクリプトの終了後に(ではなくps)端末で発行されるジョブをリストします。
アントニオ14年

1
ジョブは現在のシェルに関連付けられており、1つのシェルから別のシェルに送信されません。サブシェルが終了すると、そのジョブは回復されません。バックグラウンドプロセスのPIDを印刷することにより、サブシェルが終了した後(pid -p)でも簡単に情報を取得できるようにします。
ジョンWHスミス14年

良い説明ですが、スクリプトにさらにコマンドが含まれている場合、それらが実行されることはありません(のためwait)。待機を削除すると、信号処理が壊れます:/
chefarov
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.