サブシェルを自動的に終了しますか?

サブシェルを自動的に終了しますか?

私はこのようなことを達成したい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

答え1

メモ:

  • wait $subshell$subshell実行中のプロセスの子ではないため、機能しませんwait。とにかくこれを行うプロセスを待たないので、wait実際には重要ではありません。
  • kill $subshellサブシェルは終了しますが、sleepサブシェルの実行中に正常に起動した場合は終了しません。ただし、同じプロセスでkill実行できますsleepexec
  • SIGTERM の代わりに SIGPIPE を使用すると、メッセージを回避できます。
  • リストコンテキストで引用されていない変数はにありますbash

すべてを言うと、次のことができます。

(
  subshell=$BASHPID
  kill -s PIPE "$subshell" &
  sleep 600
)
echo subshell done

(サブシェルだけでなくシャットダウンしたい場合sleep 60に置き換えてください。この場合、サブシェルをシャットダウンしたときにサブシェルが実行されるまでの時間さえない場合があります。)exec sleep 60killsleepsleep

とにかく、あなたがそれで何を達成したいのか分かりません。

sleep 600 &

sleepそれが必要な場合(またはメインシェルでプロセスを非表示にし(sleep 600 &)たい場合sleep)、バックグラウンドで実行する方がより安定したアプローチになります。

今実際の状況で

sudo stdbuf -o0 wpa_supplicant -Dwext -i"$wifi" -c/etc/wpa_supplicant/wpa_supplicant.conf

コマンドを実行する場合は、子プロセスをsudo作成してコマンドを実行します(状態を記録するか、後でいくつかのPAMセッション操作を実行する必要がある場合にのみ)。stdbufただし、同じプロセスで実行されるため(残りのスクリプトに加えて)祖先には3つのプロセスがありますwpa_supplicantwpa_supplicant

  1. サブシェル
  2. 1歳の時 sudo
  3. wpa_supplicant(stdbufを実行する前)を2の子として使用する

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サブシェルと同じプロセスで実行されます。$BASHPIDexec

パイプを介してpidを取得し、killrootとして実行します。

もう少し待つ覚悟をしていたら、

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"

SIGPIPE を使用して自動的に終了しますwpa_supplicant(システムによって、権限の問題はありません)。次回grep消えたら、そのパイプに何かを書き込みます。

sudo一部のシェル実装では、1つが返されるのを待たずgrep(SIGPIPEDが受信されるまでバックグラウンドで実行されるようにします)、1つが返されるのを待たない構文を使用してこれを実行することもbashできます。grep ... <(sudo ...)bashsudogrep

詳細については、次を参照してください。一致するものを見つけた後、Grepはゆっくり終了しますか?

答え2

bash -iサブシェルは、プロンプトを表示する対話型ログインシェルなどのシェルのサブシェルコマンドです$。あなたはしません持つサブシェルでコマンドを実行 - スタンドアロンプ​​ロセスとして実行することを選択できます。 stdout / stderrが進行状況バーの外観をめちゃくちゃにしたくないので、親シェルが子シェルの死を報告したり通知したくないので、これは適切であると思われます。

これを達成するためのいくつかの標準ツールがあります。悪魔そしていいえ。 (あなたも見ることができます男性 ページ.) あなたができる最善は北面。以下は、これを使用して単純なプログラムを実行する例です。いいえnohup.outを生成します。

$ nohup true 2>&1 > /dev/null &

プログラムまたはプログラムのラッパースクリプトが適切なPIDを/tmp/my.pidに書き込むようにしてください。 bashでは、これを変数として使用できます$$。次に、進行状況バーを使用してプロセスを監視します。

$ kill `cat /tmp/my.pid`

もはやプログラムで処理が必要ない場合。またはプログラム名をkillall

答え3

あなたはこれを探しているかもしれません

#!/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

この例は、印刷する前に1秒間一時停止されますsubshell done。この例はまた、バックグラウンドプロセスを実行し、同じ行で待機する方法を示しています(例:& wait 2>wait_outputこれが関連しているかどうかわかりません)wait $!

ここで注目すべき重要な点は、メッセージがTerminated最上位の親シェル操作制御から来ることです。これがサブシェルが終了してメッセージを生成する理由です。これが出力をキャプチャしたい場所です。waitコマンド出力をリダイレクトすると、これは完了です。

関連情報