次から始めましょう:
% donothing () { echo $$; sleep 1000000 }
% donothing
47139
この時点でシェルを制御する同じ端末をクリックすると、関数が終了してCtrl-C
コマンドdonothing
プロンプトに戻ります。
しかし、代わりに別のシェルセッションで次を実行すると、
% kill -s INT 47139
...このdonothing
機能はいいえ終了。 (-47139
最後の引数として渡すと上記と同じですkill
。)
kill -s INT
制御端末で対話的に同じ効果を得るには、使用しているPIDとは異なるPIDを使用する必要がありますか?Ctrl-C
(私は主に答えに興味がありますzsh
。)
編集:Gillesのコメントへの回答:いいえ、トラップを設定していません(トラップが設定されていないことを確認する方法を学びたい。すべてのアクティブトラップを一覧表示する方法はありますか?はい、再現できます)。この動作はzsh -f
。実際、完全に「裸」の効果を得るために、私が知っている最も極端な方法でそれを再現することができます。zsh
(より良い方法があれば教えてください。)
% /usr/bin/env -i /usr/bin/zsh -f
% donothing () { echo $$; sleep 1000000 }
12345
...など。
元の投稿以降、DarwinとNetBSDは上記の動作を複製しましたが、Linuxでは複製しませんでした(つまり、Linuxでは上記で定義した関数を終了しますが、kill -s INT <zsh PID>
プロセスdonothing
の親シェルは終了しません)。
おそらくこれはBSDスタイルです。具体的には、私が試したすべてのUnixでは、プロセスはプロセスのsleep
子ですが、zsh
LinuxでのみプロセスSIGINT
に送信された信号がプロセスに伝播されます。zsh
sleep
したがって、DarwinとNetBSDでこの関数を非対話式で終了させるには、donothing
-ingサブプロセスのPIDを見つけてそのプロセスにsleep
送信する方法が必要ですSIGINT
(もちろん、これは本当に冷静に聞こえます)。より一般的には、DarwinとNetBSDで非対話式でシェル機能を終了するには、再帰的/深く優先検索を実行する必要があります。子孫処理zsh
して送ってくださいSIGINT
...
答え1
Control-cスリープ処理を含む端末から、端末に関連するプロセスグループに割り込み信号を送信します。 killを介してSIGINTを送信すると、1つのプロセスにのみ到達できます。この場合、$ $は休止プロセスではなくシェルのプロセスIDを返すため、無効なプロセスになります。シェルは通常 SIGINT を無視します。
答え2
デフォルトでは、次のことができます。いいえ特定のシェル関数にシグナルを送信します。関数は手続き型論理ブロックを構築するのに便利なツールです。これはシェルスクリプトと似ていますが、同じではありません。
シェルスクリプトを実行すると、現在実行中のシェル/インタプリタが分岐し、サブシェル/インタプリタがスクリプトを実行できるようになります。 Forking はまったく新しいプロセスを作ることを意味します。プロセスは任意の信号を送信することができます。
シェル機能を実行すると(暗黙的)分岐がないため、専用のプロセスがないため、シグナルを送信できるターゲットはありません。
ターミナルを押すと、Ctrl-C
忙しいプロセスはシェル自体であり、現在実行中のすべての操作を停止します。あなたの例では、sleep
信号が受信されたか(関数が最後に到達して終了するように)、または関数の実行が停止したかどうかを話すことは困難です。
$ domuch () { for (( i=0; i<1000000; i++)) {} }
とにかくブロックされ、Ctrl-C
送信する信号がまったくありません。
シグナルを送信するには、スクリプトに行を入れるか、バックティック(ここで表示する方法がわかりません:-/)または代替記号を使用してサブシェルを含める必要があります$()
。
$ doless () { $(sleep 1000) }
$!
最後に開始されたバックグラウンドプロセスのPIDを示す特別な引数を使用できますが、同じシェル内でのみ可能で、次のことができます。
$ doless &
$ kill -int $!
[1] 30769
[1] + interrupt dosome
まだ信号を受信する機能ではありませんsleep
。
興味深いことに、下のような関数の中から背景にスリープを渡すと
dotoomuch() () { $(sleep 1000) & }
Ctrl-C
ifで端末を遮断しても中断することはできません。これが望ましい動作であるかどうかはわかりません(zsh 4.3.10)。