获取SSH转发信号


22

我希望能够通过ssh发送信号(SIGINT最重要)。

该命令:

ssh server "sleep 1000;echo f" > foo

将开始在服务器上进入睡眠状态,并在1000秒后将“ f \ n”放入本地计算机上的foo文件中。如果按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"

编辑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命令。)如果我是的,请使您的示例更能代表您的实际用法,以便提供更好的答案。
沃伦·扬

正确:睡眠和回声实际上是用户提供的脚本,实际上不是睡眠和回声。因此,我们不知道他们在做什么,应该承担最坏的情况。
Ole Tange 2012年

如此...您将提出一个更好的示例命令,对吧?一个简单的重新排列不能解决问题的地方?您提出了一个很好的问题,我希望看到它得到答复,但是如果“那么不这样做,那么”是一个合理的答复,那么您不太可能得到答复。
沃伦·扬

哦,顺便...不要那样做;)
蒂姆(Tim

正如问题中所阐明的:““”上面我使用了“ sleep 1000; echo f”,但实际上由用户提供,因此它可以包含任何内容“”“”
Ole Tange

Answers:


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. 您实际上SIGINTtrap '/bin/true' SIGINT用空语句捕获信号。如果没有陷阱,则在您的SIGINT信号之后您将没有任何标准输出。

似乎不能很好地处理二进制输入:seq 1000 | gzip | ssh -t -t服务器“ stty isig intr ^ N -echoctl;陷阱'/ bin / true'SIGINT; sleep 1; zcat | bzip2” | bzcat> foo;
Ole Tange 2012年

如果您为ssh而非控制台设置了标准输入,则无法通过控制台中断。在这种情况下,您必须被stdin流打断。
digital_infinity 2012年

我发现这seq 1000 | gzip | ssh -tt dell-test "zcat|bzip2" | bzcat > foo也行不通。要使此命令起作用,我们需要将其删除-tt。因此,伪终端分配可能会从stdin中获取一些输入
digital_infinity 2012年

我尝试了uuencode。在此版本中,它不起作用:cat foo.gz | perl -ne'print pack(“ u”,$ _)'| ssh -t -t服务器'perl -ne“ print unpack(\” u \“,\ $ _)” | zcat | gzip | perl -ne“打印包(\” u \“,\ $ _)”'| perl -ne'print unpack(“ u”,$ _)'> foo2.gz
Ole Tange

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

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万一连接丢失,那不会停止该过程。
2016年

当连接断开时,stdin断开,从而阻止了猫的活动,这将杀死进程组。该INTerrupt信号是否足以胜任您的任务是另一个问题。
埃里克·伍德拉夫

sleep对它应该足够好了,不是吗?我已经添加了一些date >> /tmp/killed之后cat,但它不会被触发。是否有超时时间?我通常使用Zsh,但也使用bash作为远程登录外壳对其进行了测试。
2016年

我认为您受连接超时的支配。
埃里克·伍德拉夫

有设置可以控制此设置吗?对于客户端-o ServerAliveInterval=3 -o ServerAliveCountMax=2,它可以快速检测到它,但是对于服务器端,有什么东西吗?
2016年

2

我认为您可以找到正在服务器上运行的进程的PID,并使用另一个ssh命令发送信号(例如:)ssh server "kill -2 PID"

我使用这种方法向运行在另一台机器上的应用程序发送重新配置信号(我的应用程序捕获了SIGUSR1并读取了配置文件)。就我而言,查找PID很容易,因为我具有唯一的进程名称,并且可以通过发送ps请求来找到PID ssh


我找不到找到在远程运行的程序的PID的防弹方法。请记住,它是由用户提供的。可能是:ssh服务器'exec $(echo fyrrc 1000 | / usr / games / rot13)'
Ole Tange

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

嗨!我认为您可以通过尽可能多地解释认为有效的方法来使答案更加有用。不要犹豫对其进行编辑以插入新信息。
dhag 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.