綺麗に死ぬシェルスクリプトの作り方

シェルスクリプトで外部コマンドをつくったとき、cmd & でバックグランドで起動したものを kill $! で止めようとしても/bin/shプロセスしか止まらずその中で動いていたプロセスは動きっぱなしになる。さてどうするとよいか?
プログラミング
2
鯉江 @koie
@satoh_fumiyasu シェルってシグナルくらっても子供殺してくれないんだっけ? ideone.com/KSCYBR -pidでprocgroupにシグナルとんでくれないし。なんかいろいろわからん。
SODA Noriyuki @n_soda
@koie @satoh_fumiyasu むしろ、なぜ子供を殺してくれると思ったのかが気になります。ttyドライバが投げるシグナルや、session leader が死んだときのシグナルと勘違いしてるとか?それらはカーネルが投げているわけで、シェルじゃないです。
鯉江 @koie
@n_soda @satoh_fumiyasu C-cでフォアグラウンドグループにシグナルとぶのは理解してて、session leaderが死ぬとシグナル飛ぶのはしらなかったけど今回は関係ないとおもうし、シェルがフォアグラウンドのコマンドを殺してくれないならどうかけばいいんやろ?
SODA Noriyuki @n_soda
@koie @satoh_fumiyasu プロセスグループを新しく作っておいて、trapコマンド使ってシグナルをトラップして、トラップハンドラで「kill -プロセスグループID」とか?
鯉江 @koie
@n_soda @satoh_fumiyasu trap書いても受け取ってくれない、というのも補足。 ideone.com/VI3wgJ
SODA Noriyuki @n_soda
@koie @satoh_fumiyasu trap しているコードはどこにありますか?
鯉江 @koie
@n_soda @satoh_fumiyasu kill -pgid を理解してくれないっぽい。 ideone.com/rNo1c5
鯉江 @koie
@n_soda @satoh_fumiyasu セッションリーダしんだらHUPくるんだったけ?端末が閉じたら?
鯉江 @koie
@n_soda @satoh_fumiyasu いま悪魔本みてセッションの制御プロセスが死んだら、フォアグランドグループにHUPってかいてあるのを確認しました。
SODA Noriyuki @n_soda
@koie @satoh_fumiyasu ちゃんとtrapできてます。シグナル受け取ったシェルは、sar -n DEV 1の終了を待ってからtrapハンドラ呼び出してます。 bashなら、「sar -n DEV 1」を「sar -n DEV 1 & wait」にすればいいみたい
SODA Noriyuki @n_soda
@koie @satoh_fumiyasu 「ps -ef|grep sar」で見てるから誤解してるだけです。「ps -o pid,pgid,cmd」で見れば、そんなプロセスグループは存在しないことが分かります。エラーも文法エラーじゃなくて ESRCH でしょう?
ふみやす@シェルまおう(自称でない) FGO:838,149,789 @satoh_fumiyasu
@n_soda @koie 私はそうしてますね。自身がプロセスグループリーダー(? セッションリーダー? ちょっとこの辺りの理解・記憶はいつも怪しい)は確認せずに kill -TERM -$$ とかしてるかな。確認しないのはよくないのかな。
鯉江 @koie
@n_soda @satoh_fumiyasu sar.shをstraceしたらwait4がERESTARTSYSになってたのでシグナルをマスクしてるんじゃなくてプロセスが終わるのをまってから処理するかんじなんですかね。しかしすべての文に&waitはつらい。。
SODA Noriyuki @n_soda
@satoh_fumiyasu @koie どうやってリーダーになってるかによりけりじゃないでしょうか。setsid(1) なら確実にセッションリーダーにはなるけど、ちょっと副作用大きいような。シェルのレベルで確実にプロセスグループリーダーになる方法って、何がありましたっけ?
鯉江 @koie
@n_soda @satoh_fumiyasu さっきのまちがってたので削除して書き直します。ジョブコンあるんだからバックグラウンドで起動するときはプロセスグループつくるとおもってました。
ふみやす@シェルまおう(自称でない) FGO:838,149,789 @satoh_fumiyasu
@n_soda @koie 理解・記憶があやふやなまま「これでいいのかなー」で実装しているので…。方法ですが、過去にざっくり調べた記憶によると、シェルにはたぶんないです。
鯉江 @koie
@satoh_fumiyasu @n_soda けっきょくのところ、こうかかないといけないってことでいいんでしょうか? ideone.com/9AWtse プロセスグループつくってexecするだけのコマンドつくったほうがいいかな。。。
SODA Noriyuki @n_soda
@koie @satoh_fumiyasu ちなみにNetBSDの/bin/sh (ash派生)でやったらダメでした。シグナル届いてもwaitが終了してくれません。POSIXにはwaitコマンド自身がシグナル受け取った場合の記述はないので、移植性ありませんね。うーむ…
SODA Noriyuki @n_soda
@koie @satoh_fumiyasu プロセスグループ作ってexecするだけのコマンド作る方がおススメですね。この機能、標準的に存在してもいいような気はします。
ふみやす@シェルまおう(自称でない) FGO:838,149,789 @satoh_fumiyasu
@koie @n_soda シェルの動きはともかく、何がしたいのかよくわからないのですが、foo.sh から sar.sh の sh と子プロセスすべてまとめて殺したいということですかね。sar.sh で exec sar … するのは駄目ですか?
鯉江 @koie
@satoh_fumiyasu @n_soda あ、実際には sarの出力をパイプでawkにつないでいるので、execだとだめですよね?
ふみやす@シェルまおう(自称でない) FGO:838,149,789 @satoh_fumiyasu
@koie @n_soda パイプラインのすべてのコマンドで exec すれば動くかもしれませんが、それでも sh が残る実装があったかなぁ???? 残らなくても、確実にすべて殺されはしないので、いまいちですね。
ふみやす@シェルまおう(自称でない) FGO:838,149,789 @satoh_fumiyasu
@n_soda @koie ちなみに dash は wait 中でもシグナルハンドラー呼ばれました。
残りを読む(12)

コメント

コメントがまだありません。感想を最初に伝えてみませんか?

ログインして広告を非表示にする
ログインして広告を非表示にする