Sshを介してシグナル(SIGINTが最も重要)を送信できるようにしたい。
このコマンド:
ssh server "sleep 1000;echo f" > foo
サーバーでスリープを開始し、1000秒後にローカルマシンのファイルfooに「f\n」を配置します。 CTRL-Cを押すと(つまり、SIGINTをsshに送信)、sshは強制終了されますが、リモートサーバーのスリープは強制終了されません。リモートサーバーのスリープを強制終了したい。
だから私は試した:
ssh server -t "sleep 1000;echo f" > foo
しかし、stdinがターミナルでない場合、次のエラーが発生します。
Pseudo-terminal will not be allocated because stdin is not a terminal.
その後、SIGINTはまだ転送されません。
だから私は試した:
ssh server -t -t "sleep 1000;echo f" > output
しかし、fooの出力は 'f\n'ではなく 'f\r\n'です。これは私の状況では悲惨です(私の出力はバイナリデータであるため)。
上記では「sleep 1000; echo f」を使用していますが、実際にはユーザーが指定するため、何でも含めることができます。ただし、「sleep 1000; echo f」で機能させることができれば、現実的なすべての状況で機能させることができます。
私は実際にはもう一方の端で疑似端末を取得することには関心がありませんが、sshにSIGINTを転送させる他の方法を見つけることができませんでした。
別の方法はありますか?
編集:
ユーザーは、次のようなstdinからバイナリデータを読み取るコマンドを与えることができます。
seq 1000 | gzip | ssh server "zcat|bzip2; sleep 1000" | bzcat > foo
ユーザーは、CPUを多用する次のようなコマンドを与えることができます。
ssh server "timeout 1000 burnP6"
Edit2:
私にとってうまくいくように見えるバージョンは次のとおりです:
your_preprocessing |
uuencode a | ssh -tt -oLogLevel=quiet server "stty isig -echoctl -echo ; uudecode -o - |
your_command |
uuencode a" | uudecode -o - |
your_postprocessing
私を正しい方向に向けてくれたdigital_infinityに感謝します。
短い答え:
ssh -t fs "stty isig intr ^N -echoctl ; trap '/bin/true' SIGINT; sleep 1000; echo f" > foo
cTRL + Nでプログラムを停止します。
長い説明:
stty
オプションintr
を使用して、サーバーまたはローカル割り込み文字を変更して、互いに衝突しないようにする必要があります。上記のコマンドで、サーバーの割り込み文字をCTRL + Nに変更しました。ローカルの割り込み文字を変更し、サーバーの文字を変更せずに残すことができます。stty -echoctl
を使用します。stty isig
trap '/bin/true' SIGINT
によってSIGINT
信号をキャッチします。トラップがないと、SIGINTシグナルの後にstdoutがなくなります。私はすべての解決策を試しましたが、これが最高でした:
ssh Host "sleep 99 < <(cat; kill -INT 0)" <&1
ソリューションは https://www.gnu.org/software/parallel/parallel_design.html#The-remote-system-wrapper に進化しました
$SIG{CHLD} = sub { $done = 1; };
$pid = fork;
unless($pid) {
# Make own process group to be able to kill HUP it later
setpgrp;
exec $ENV{Shell}, "-c", ($bashfunc."@ARGV");
die "exec: $!\n";
}
do {
# Parent is not init (ppid=1), so sshd is alive
# Exponential sleep up to 1 sec
$s = $s < 1 ? 0.001 + $s * 1.03 : $s;
select(undef, undef, undef, $s);
} until ($done || getppid == 1);
# Kill HUP the process group if job not done
kill(SIGHUP, -${pid}) unless $done;
wait;
exit ($?&127 ? 128+($?&127) : 1+$?>>8)
サーバー上で実行しているプロセスのPIDを見つけて、別のssh
コマンドを使用してシグナルを送信できると思います(次のような:ssh server "kill -2 PID"
)。
この方法を使用して、別のマシンで実行されているアプリケーションに再構成信号を送信します(私のアプリケーションはSIGUSR1をキャッチして構成ファイルを読み取ります)。私の場合、一意のプロセス名があり、ps
経由でssh
リクエストを送信してPIDを見つけることができるため、PIDを見つけるのは簡単です。
----- command.sh
#! /bin/sh
trap 'trap - EXIT; kill 0; exit' EXIT
(sleep 1000;echo f) &
read ans
-----ローカル端末上
sleep 864000 | ssh -T server command.sh > foo