このようなものを実装したい Q/A ただし、サブシェル用です。これが私が試していることの最小限の例です:
(subshell=$BASHPID
(kill $subshell & wait $subshell 2>/dev/null) &
sleep 600)
echo subshell done
どうすればsubshell done
は次の代わりに戻ります。
./test.sh: line 4: 5439 Terminated ( subshell=$BASHPID; ( kill $subshell && wait $subshell 2> /dev/null ) & sleep 600 )
subshell done
編集:ここでの用語は間違っているかもしれませんが、サブシェルとは、ブラケットの最初のセット内のプロセスを意味します。
更新:
コンテキストのために実際のプログラムからスニペットを投稿したいのですが、上記は単純化したものです。
# If subshell below if killed or returns error connected variable won't be set
(if [ -n "$2" ];then
# code to setup wpa configurations here
# If wifi key is wrong kill subshell
subshell=$BASHPID
(Sudo stdbuf -o0 wpa_supplicant -Dwext -i$wifi -c/etc/wpa_supplicant/wpa_supplicant.conf 2>&1 \
| grep -m 1 "pre-shared key may be incorrect" \
&& kill -s PIPE "$subshell") &
# More code which does the setup necessary for wifi
) && connected=true
# later json will be returned based on if connected is set
注意:
wait $subshell
_はwait
を実行しているプロセスの子ではないため、_$subshell
_は機能しません。とにかく、wait
を実行するプロセスを待つ必要はないので、それほど重要ではありません。kill $subshell
_はサブシェルを強制終了しますが、sleep
が実行されるまでにサブシェルがサブシェルを開始できた場合は、kill
を強制終了しません。ただし、sleep
と同じプロセスでexec
を実行できます。bash
で非常に特別な意味を持ちます。以上のことをすべて言ったので、次のことができます。
_(
subshell=$BASHPID
kill -s PIPE "$subshell" &
sleep 600
)
echo subshell done
_
(kill
でsleep
を殺すには、_sleep 60
_を_exec sleep 60
_に置き換えます。サブシェルだけではなく、sleep
を殺します。
いずれにしても、それで何を達成したいのかわかりません。
_sleep 600 &
_
sleep
をバックグラウンドで開始する場合は、より信頼性の高い方法です(または、そのsleep
プロセスをメインシェルから非表示にする場合は_(sleep 600 &)
_)。
今あなたの実際の
_Sudo stdbuf -o0 wpa_supplicant -Dwext -i"$wifi" -c/etc/wpa_supplicant/wpa_supplicant.conf
_
コマンドでは、Sudo
がコマンドを実行するための子プロセスを生成することに注意してください(ステータスをログに記録するか、後でいくつかのPAMセッションタスクを実行する必要がある場合のみ)。ただし、stdbuf
は同じプロセスで_wpa_supplicant
_を実行するため、最終的には_wpa_supplicant
_の祖先に(スクリプトの残りの部分に加えて)3つのプロセスがあります。
1を殺しても、自動的に2は殺されません。ただし、2を殺した場合、傍受できないSIGKILLのようなシグナルがない限り、Sudo
が受信したシグナルをコマンドに転送するため、3が殺されます。実行します。
いずれにせよ、それはあなたがここで殺したいサブシェルではありません、それは3または少なくとも2です。
これで、root
として実行されていて、スクリプトの残りの部分が実行されていない場合、スクリプトを簡単に強制終了することはできません。
kill
をroot
として実行する必要があるため、次のものが必要です。
_Sudo WIFI="$wifi" bash -c '
(echo "$BASHPID" &&
exec stdbuf -o0 wpa_supplicant -Dwext -i"$WIFI" -c/etc/wpa_supplicant/wpa_supplicant.conf 2>&1
) | {
read pid &&
grep -m1 "pre-shared key may be incorrect" &&
kill -s PIPE "$pid"
}'
_
そうすれば、_wpa_supplicant
_は、exec
で作成しているのと同じ_$BASHPID
_プロセスでサブシェルとして実行されます。
パイプを通じてpidを取得し、kill
をルートとして実行します。
もう少し待つ準備ができている場合は、
_Sudo stdbuf -o0 wpa_supplicant -Dwext -i"$wifi" -c/etc/wpa_supplicant/wpa_supplicant.conf 2>&1 |
grep -m1 "pre-shared key may be incorrect"
_
_wpa_supplicant
_はSIGPIPEで自動的に強制終了されます(システムによって、許可の問題はありません)次回後にそのパイプに何かを書き込みますgrep
はなくなりました。
一部のシェル実装は、Sudo
が戻った後(SIGPIPEdを取得するまでバックグラウンドで実行したまま)grep
を待機しません。また、bash
を使用すると、grep ... <(Sudo ...)
構文を使用して待機することもできます。bash
は待機しません。 Sudo
が戻った後のgrep
の場合。
サブシェルとは、bash -i
プロンプトを提供する$
インタラクティブログインシェルの子など、一部のシェルの子であるシェルコマンドを指します。サブシェルでコマンドを実行するhaveする必要はありません-独立したプロセスとして実行することを選択できます。 stdout/stderrがプログレスバーの外観を台無しにしたくないため、また親シェルがその子の死について報告したり、気づいたりすることを望まないため、これは適切であるように思われます。
daemonize やNohupなど、これを実現するための標準ツールがあります。 ( manpages も参照してください。) Nohup を使用するのが最適な場合があります。これを使用して、notnohup.outを作成する簡単なプログラムを実行する例を次に示します。
$ Nohup true 2>&1 > /dev/null &
プログラムまたはプログラムのラッパースクリプトで、そのPIDを/tmp/my.pidに記録します。bashはそれを$$
変数として使用できるようにします。次に、プログレスバーを使用した監視プロセスで
$ kill `cat /tmp/my.pid`
そのプログラムがそれ以上処理を行う必要がなくなったとき。または、プログラム名をkillall
に指定することもできます。
あなたはこれを探しているかもしれません
#!/bin/bash
(subshell=$BASHPID
(kill $subshell & wait $subshell 2>/dev/null) &
sleep 600) &
wait $! 2>/dev/null
echo subshell done
ここでサブシェルはバックグラウンドに置かれ、親シェルは待機しますが、待機出力は/ dev/nullに送信されます。これにより、Terminated
メッセージがキャッチされます。
ファイルへの出力をキャプチャするために待機を変更した場合、たとえばwait $! 2>wait_output
すると、
./foo.sh: line 5: 1939 Terminated ( subshell=$BASHPID; ( kill $subshell & wait $subshell 2> /dev/null ) & sleep 600 )
Terminated
が親シェルからのものであることを示しています。
殺す前に何らかの活動がある場合に機能することを確認するための小さなチェック
#!/bin/bash
(subshell=$BASHPID
(sleep 1; kill $subshell & wait $subshell 2>/dev/null) &
sleep 600) & wait 2>wait_output
echo subshell done
この例は、subshell done
を出力する前に1秒間停止します。この例では、背景をすべて同じラインで待機する方法も示しています。 & wait 2>wait_output
。 wait $!
の例に比べて長所/短所があるかどうかはわかりません。
ここで注意すべき重要な点は、Terminated
メッセージが最上位の親シェルジョブコントロールから送信されることです。これが、サブシェルが終了し、メッセージを生成するのを確認するものです。したがって、ここで出力をキャッチします。 wait
コマンド出力をリダイレクトすると、これが行われます。