バックグラウンドプロセスがシェルで終了するまでフォアグラウンドプロセスを実行します。

バックグラウンドプロセスがシェルで終了するまでフォアグラウンドプロセスを実行します。

QEMU仮想マシンをモードで実行し、-daemonizeQEMUインスタンスと対話するように設計されたランダムなフォアグラウンド(対話型)プロセスを作成します。通常、フォアグラウンドプロセスが完了すると、pidfileを介してQEMUインスタンスをクリーンアップします。

qemu-system ... -pidfile ./qemu.pid -daemonize

/my/custom/interactive/process

pkill -F ./qemu.pid

ただし、場合によっては、フォアグラウンドプロセスの実行中にQEMUが独立して終了することがあります。でも、万が一に備えてブロックしたいです。したがって、私のカスタムインタラクションプロセスは次のように機能するはずです。

tail -f --pid=./qemu.pid /dev/null

どうすればうまくできますか?おそらくタイムアウトの一種のラッパーがあるので、次のように実行できます。

trackpid ./qemu.pid /my/custom/interactive/process

答え1

qemuプロセスをポーリングして消えるかどうかを確認し、消えたら早く終了することができます。特にqemu-system

それもかなりたくさんあります。この行を削除できますが#DEBUG、これらの行がどのように結合されているかを確認するには、コメントを外してプログラムの出力をコードと比較します。

#!/bin/bash

InvokeQemu()
{
    local i pid pidFile=qemu.pid

    # Start the qemu process, and return the PID if possible
    #
    (
        # qemu-system ... -pidFile "$pidFile" -daemonize
        ( sleep 30 & sleep 0.5 && echo $! >"$pidFile" )    # FAKE IT for half a minute
    ) >/dev/null 2>&1 </dev/null

    #echo "InvokeQemu: checking for successful daemonisation" >&2    #DEBUG
    for i in 1 2 3
    do
        # Does the PID file exist yet
        #echo "InvokeQemu: attempt $i" >&2    #DEBUG
        if [[ -s "$pidFile" ]] && pid=$(cat "$pidFile") && [[ -n "$pid" ]]
        then
            printf "%s\n" $pid
            #echo "InvokeQemu: pid=$pid" >&2    #DEBUG
            return 0
        fi

        # Pause a moment or so before trying again
        sleep 2
    done
    return 1
}

MonitorPIDs()
{
    local pid

    for pid in "$@"
    do
        #echo "MonitorPIDs: checking pid $pid" >&2    #DEBUG
        if err=$(kill -0 "$pid" 2>&1) || [[ "$err" == *permitted* || "$err" == *denied* ]]
        then
            # Process still exists
            :
            #echo "MonitorPIDs: pid $pid still alive" >&2    #DEBUG
        else
            #echo "MonitorPIDs: pid $pid has died" >&2    #DEBUG
            echo "$pid"
            return 1
        fi
    done
    #echo "MonitorPIDs: all good" >&2    #DEBUG
    return 0
}

########################################################################
# Go
myPid=$$

# Start the qemu emulator
echo "Starting qemu emulator"
qemuPid=$(InvokeQemu)

if [[ -z "$qemuPid" ]]
then
    echo "Could not start qemu" >&2
    exit 1
fi

# Start the monitor process
#
# Once any of them is no longer running it will fire SIGTERM to its
# remaining PIDs and then exit
echo "Starting monitor process"
(
    while MonitorPIDs $qemuPid $myPid >/dev/null
    do
        #echo "(Monitor): all good" >&2    #DEBUG
        sleep 2
    done
    kill $qemuPid $myPid 2>/dev/null
) &

# Start your interactive foreground process
#
# You will receive SIGTERM within a few seconds of the emulator exiting,
# so you may want to trap that
echo "Starting interactive process"
while read -p "What do you want to do? " x
do
    echo "OK"
    sleep 1
done
exit 0

答え2

最後に、次のコードを取得しました。

qemu-system ... -pidfile ./qemu.pid -daemonize

{
  tail -f --pidfile="$(cat ./qemu.pid)" /dev/null
  kill -INT 0
} &

/my/custom/interactive/process
kill $!

pkill -F ./qemu.pid

中かっこ内のスクリプトは、実際にバックグラウンドで実行されるpidfileモニタです。 pidが消えると、モニタは現在のプロセスグループを終了します。kill -INT 0最も信頼性が高くクリーンな結果を提供するために使用します。

他のオプションは次のとおりです。

kill -- 0(TERM信号を使用して終了すると、対話型プロセスを正しく終了できません)

kill -INT $$(シェルプロセスのみ終了し、対話型プロセスは正しく終了できません)

kill -- -$$sudo(シェルのpidで表示されるプロセスグループを殺すことは、プロセスグループリーダーとして呼び出されるため、常に正しく機能していないようです)

pkill -P $$(サブプロセスのみを終了することは実際には機能しますが、組み込みシェルを使用してCtrl-Cを使用してアクションを処理することをお勧めします。)

もう1つのポイントは、対話型プロセスが独自に完了したら、シャットダウンスクリプトとクリーンアップスクリプトの追加の推論を避けるためにモニタプロセスを終了する必要があることです。

関連情報