使用bash在ssh上启动进程,然后在sigint上将其杀死

get*_*kha 12 ssh bash signals

我想使用ssh在不同的机器上启动几个作业.如果用户然后中断主脚本我想要优雅地关闭所有作业.

以下是我正在尝试做的一个简短示例:

#!/bin/bash
trap "aborted" SIGINT SIGTERM
aborted() {
    kill -SIGTERM $bash2_pid
    exit
}

ssh -t remote_machine /foo/bar.sh &
bash2_pid=$!
wait
Run Code Online (Sandbox Code Playgroud)

但是bar.sh进程仍在运行远程计算机.如果我在终端窗口中执行相同的命令,它将关闭远程主机上的进程.

当我运行bash脚本时,是否有一种简单的方法可以实现这一点?或者我是否需要让它登录到远程计算机,找到正确的进程并以这种方式杀死它?

编辑:似乎我必须使用选项B,通过另一个ssh连接杀死remotescript

所以我不想知道如何获得remotepid?我尝试了一些类似的东西:

remote_pid=$(ssh remote_machine '{ /foo/bar.sh & } ; echo $!')
Run Code Online (Sandbox Code Playgroud)

这不起作用,因为它阻止.

如何等待变量打印然后"释放"子流程?

lhu*_*ath 17

绝对最好保持你的清理由启动进程的ssh管理,而不是稍后用第二个ssh会话进入kill.

当ssh连接到您的终端时; 它表现得很好.但是,将它从终端中分离出来(正如您所注意到的那样)会发出信号或管理远程进程的痛苦.您可以关闭链接,但不能关闭远程进程.

这将为您提供一个选项:使用链接作为远程进程获取其需要关闭的通知的方式.最简单的方法是使用阻塞I/O. 从ssh进行远程读取输入以及何时需要关闭进程; 发送一些数据,以便远程的读取操作解除阻塞,并且可以继续进行清理:

command & read; kill $!
Run Code Online (Sandbox Code Playgroud)

这就是我们想要在遥控器上运行的内容.我们调用我们想要远程运行的命令; 我们读了一行文本(块直到我们收到一个),当我们完成时,发出命令终止信号.

要将信号从我们的本地脚本发送到远程,我们现在需要做的就是向它发送一行文本.不幸的是,Bash在这里没有给你很多好的选择.至少,如果你想与bash <4.0兼容,那就不是了.

使用bash 4,我们可以使用协同进程:

coproc ssh user@host 'command & read; kill $!'
trap 'echo >&"${COPROC[1]}"' EXIT
...
Run Code Online (Sandbox Code Playgroud)

现在,当地的脚本退出时(不要上圈套INT,TERM等刚EXIT)发送一个新的生产线在的第二个元素的文件COPROC阵列.这个文件是连接到管道sshstdin,有效的路由我们的线ssh.remote命令读取该行,结束readkills命令.

在bash之前,由于我们没有协同进程,因此事情变得更加艰难.在这种情况下,我们需要自己做管道:

mkfifo /tmp/mysshcommand
ssh user@host 'command & read; kill $!' < /tmp/mysshcommand &
trap 'echo > /tmp/mysshcommand; rm /tmp/mysshcommand' EXIT
Run Code Online (Sandbox Code Playgroud)

这应该适用于任何bash版本.


小智 6

试试这个:

ssh -tt host command </dev/null &
Run Code Online (Sandbox Code Playgroud)

当您终止本地ssh进程时,远程pty将关闭,SIGHUP将被发送到远程进程.