sshを取得して信号を転送する


22

sshを介してシグナル(SIGINTが最も重要)を送信できるようにしたい。

このコマンド:

ssh server "sleep 1000;echo f" > foo

サーバーでスリープを開始し、1000秒後にローカルマシンのファイルfooに「f \ n」を入れます。CTRL-Cを押す(つまり、sshにSIGINTを送信する)と、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」で機能させることができる場合は、現実的なすべての状況で機能させることができます。

反対側で擬似端末を取得することは本当に気にしませんが、SIGINTを転送するsshを取得する他の方法を見つけることができませんでした。

別の方法はありますか?

編集:

ユーザーは、次のような、stdinからバイナリデータを読み取るコマンドを指定できます。

seq 1000 | gzip | ssh server "zcat|bzip2; sleep 1000" | bzcat > foo

ユーザーは、次のようなCPU集中型のコマンドを指定できます。

ssh server "timeout 1000 burnP6"

編集2:

私のために働くと思われるバージョンは次のとおりです。

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に感謝します。


1
ssh単純な再配置でsleep 1000 && ssh server "echo f" > foo目的の動作を得ることができるため、実際の使用方法は例として示すものよりも複雑でなければならないと思います(殺すことでコマンドが実行され&&ない;ようにするため、ではなくである必要があります)。そうです、あなたの例が実際の使用法をより代表するようにしてください。そうすれば、より良い答えを与えることができます。sleepssh
ウォーレンヤング

正しい:スリープとエコーは実際にはユーザーが指定したスクリプトであり、文字通りスリープとエコーではありません。だから、彼らが何をするのかわからず、最悪の事態を想定すべきです。
オレ丹下

すごい...あなたはより良い例のコマンドを思い付くでしょう?単純な再配置では問題が解決しない場合は?あなたは良い質問をし、それが答えられるのを見たいのですが、「そうしないでください」と答えるなら、あなたは答えを得る可能性が低くなります。
ウォーレンヤング

ああ...そんなことしないでください;)
ティム

「」スリープ1000「私が使用して上記では『;「」エコーF』が、ユーザによって供給されている現実で、これには何を含めることができます」:質問にelabratedとして
オレ丹下

回答:


10

短い答え:

ssh -t fs "stty isig intr ^N -echoctl ; trap '/bin/true' SIGINT; sleep 1000; echo f" > foo

Ctrl + Nでプログラムを停止します。

長い説明:

  1. サーバーまたはローカル割り込み文字を変更するには、sttyオプションintrを使用する必要があります、互いに衝突し。上記のコマンドでは、サーバーの割り込み文字をCTRL + Nに変更しました。ローカル割り込み文字を変更して、サーバーの文字を変更せずに残すことができます。
  2. 割り込み文字を出力(およびその他の制御文字)に含めたくない場合は、を使用しますstty -echoctl
  3. sshdによって呼び出されたサーバーbashで制御文字がオンになっていることを確認する必要があります。そうしないと、ログアウトした後もプロセスがハングアップする可能性があります。stty isig
  4. 空のステートメントで実際にSIGINTシグナルをキャッチtrap '/bin/true' SIGINTします。トラップがなければ、SIGINTシグナルの後に標準出力はありません。

バイナリ入力をうまく処理していないようです:seq 1000 | gzip | ssh -t -t server "stty isig intr ^ N -echoctl; trap '/ bin / true' SIGINT; sleep 1; zcat | bzip2" | bzcat> foo;
オレ丹下

コンソール以外でsshの標準入力を設定した場合、コンソールで中断することはできません。この場合、stdinストリームによって中断する必要があります。
digital_infinity

これもseq 1000 | gzip | ssh -tt dell-test "zcat|bzip2" | bzcat > foo機能しないことがわかりました。このコマンドを機能させるには、を削除する必要があり-ttます。そのため、擬似端末の割り当てはおそらくstdin
digital_infinity

uuencodeを試しました。このバージョンでは機能しません:cat foo.gz | perl -ne 'print pack( "u"、$ _)' | ssh -t -t server 'perl -ne "print unpack(\" u \ "、\ $​​ _)" | zcat | gzip | perl -ne "print pack(\" u \ "、\ $​​ _)" '| perlの-ne 'アンパック印刷( "U"を、$ _)'> foo2.gz
オレ丹下

1
これがあります(sleep 1; seq 1000 ) | gzip | uuencode bin | ssh -tt dell-test "stty isig intr ^N -echoctl -echo ; trap '/bin/true' SIGINT; sleep 1; uudecode -o /dev/stdout | zcat |bzip2 | uuencode bin2 " | uudecode -o /dev/stdout | bzcat >foo。割り込み文字は機能しませんが、stdinがビジーのときに割り込み文字の送信方法が必要です。
digital_infinity

3

私はすべてのソリューションを試しましたが、これが最高でした:

ssh host "sleep 99 < <(cat; kill -INT 0)" <&1

/programming/3235180/starting-a-process-over-ssh-using-bash-and-then-killing-it-on-sigint/25882610#25882610


sleep接続が失われた場合でも、プロセスは停止しません。
16年

接続が失われると、stdinが壊れて猫のブロックが解除され、プロセスグループが強制終了されます。そのINTerrupt信号がタスクに十分であるかどうかは、別の質問です。
エリックウッドラフ

それは十分に良いsleepはずですよね?のdate >> /tmp/killed後に追加しましたがcat、トリガーされませんでした。何らかのタイムアウトが関係していますか?私は通常Zshを使用していますが、リモートログインシェルとしてbashを使用してテストしました。
16年

あなたは接続タイムアウトに翻弄されていると思います。
エリックウッドラフ

これを制御する設定はありますか?クライアント側で-o ServerAliveInterval=3 -o ServerAliveCountMax=2はそれをすばやく検出できますが、サーバー側には何かありますか?
16年

2

サーバーで実行しているプロセスのPIDを見つけて、別のsshコマンドを使用してシグナルを送信できると思います(次のように:ssh server "kill -2 PID"

この方法を使用して、別のマシンで実行されているアプリケーションに再構成シグナルを送信します(私のアプリケーションはSIGUSR1をキャッチし、構成ファイルを読み取ります)。私の場合、PIDを見つけるのは簡単です。一意のプロセス名があり、をps介してリクエストを送信することでPIDを見つけることができるからsshです。


リモートで実行されているプログラムのPIDを見つけるための防弾方法はありません。ユーザーが指定したことを忘れないでください。ssh server 'exec $(echo fyrrc 1000 | / usr / games / rot13)'
Ole

1

ソリューションはhttp://www.gnu.org/software/parallel/parallel_design.html#Remote-Ctrl-C-and-standard-error-stderrに進化しました

$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)

0

----- 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

こんにちは!関連性があると考えられる限り詳細に説明することで、答えがもっと便利になると思います。新しい情報を挿入するためにそれを編集することをheしないでください。
dhag
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.