使用bash在ssh上启动进程,然后在sigint上将其杀死 [英] Starting a process over ssh using bash and then killing it on sigint

查看:63
本文介绍了使用bash在ssh上启动进程,然后在sigint上将其杀死的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用ssh在不同的机器上启动几个作业.如果用户随后中断了主脚本,那么我想正常关闭所有作业.

这是我要做的事的简短示例:

 #!/bin/bash陷阱中止" SIGINT SIGTERMaborted(){杀死-SIGTERM $ bash2_pid出口}ssh -t remote_machine/foo/bar.sh&bash2_pid = $!等待 

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

当我运行bash脚本时,是否有一种简单的方法来实现这一目标?还是我需要使其登录到远程计算机,找到正确的进程并以这种方式杀死它?

似乎我必须使用选项B,通过另一个ssh连接杀死远程脚本

所以不,我想知道如何获取remotepid?我已经尝试了一些类似的方法:

  remote_pid = $(ssh remote_machine'{/foo/bar.sh&}; echo $!') 

这无法正常工作,因为它会阻塞.

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

解决方案

绝对最好由启动该过程的ssh来管理您的清理工作,而不是稍后进行第二个ssh会话进行杀戮./p>

当ssh连接到终端时;它表现得很好.但是,将其与终端分离,就会(如您所注意到的)成为发出信号或管理远程进程的麻烦.您可以关闭链接,但不能关闭远程进程.

这给您一个选择:使用链接作为远程进程的一种方式,以通知它需要关闭.做到这一点最干净的方法是使用阻塞I/O.在需要关闭进程时,从ssh进行远程读取输入;向其发送一些数据,以便遥控器的读取操作不受阻碍,并且可以继续进行清理:

 命令&读;杀死$! 

这是我们希望在遥控器上运行的内容.我们调用要远程运行的命令;我们读一行文本(直到收到一个文本为止,它们都是块状的),完成后,发出终止命令的信号.

要将信号从本地脚本发送到遥控器,我们现在要做的就是向其发送一行文本.不幸的是,Bash在这里没有给您很多好的选择.至少,如果您想与bash<兼容,则不行.4.0.

使用bash 4,我们可以使用协同处理:

  coproc ssh user @ host'命令&读;杀死$!陷阱'echo>&"$ {COPROC [1]}"'退出... 

现在,当本地脚本退出时(不要捕获 INT TERM 等,只需 EXIT ),它将发送一个新的行到 COPROC 数组的第二个元素中的文件.该文件是连接到 ssh stdin 的管道,有效地将我们的线路路由到 ssh .远程命令读取该行,结束命令的 read kill .

在进行bash之前,由于没有协同处理,所以4件事变得有点困难.在那种情况下,我们需要自己做管道:

  mkfifo/tmp/mysshcommandssh user @ host'命令&读;杀死$!</tmp/mysshcommand&陷阱'回声/tmp/mysshcommand;rm/tmp/mysshcommand'退出 

这几乎可以在任何bash版本中使用.

I want to start a couple of jobs on different machines using ssh. If the user then interrupts the main script I want to shut down all the jobs gracefully.

Here is a short example of what I'm trying to do:

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

ssh -t remote_machine /foo/bar.sh &
bash2_pid=$!
wait

However the bar.sh process is still running the remote machine. If I do the same commands in a terminal window it shuts down the process on the remote host.

Is there an easy way to make this happen when I run the bash script? Or do I need to make it log on to the remote machine, find the right process and kill it that way?

edit: Seems like I have to go with option B, killing the remotescript through another ssh connection

So no I want to know how do I get the remotepid? I've tried a something along the lines of :

remote_pid=$(ssh remote_machine '{ /foo/bar.sh & } ; echo $!')

This doesn't work since it blocks.

How do I wait for a variable to print and then "release" a subprocess?

解决方案

It would definitely be preferable to keep your cleanup managed by the ssh that starts the process rather than moving in for the kill with a second ssh session later on.

When ssh is attached to your terminal; it behaves quite well. However, detach it from your terminal and it becomes (as you've noticed) a pain to signal or manage remote processes. You can shut down the link, but not the remote processes.

That leaves you with one option: Use the link as a way for the remote process to get notified that it needs to shut down. The cleanest way to do this is by using blocking I/O. Make the remote read input from ssh and when you want the process to shut down; send it some data so that the remote's reading operation unblocks and it can proceed with the cleanup:

command & read; kill $!

This is what we would want to run on the remote. We invoke our command that we want to run remotely; we read a line of text (blocks until we receive one) and when we're done, signal the command to terminate.

To send the signal from our local script to the remote, all we need to do now is send it a line of text. Unfortunately, Bash does not give you a lot of good options, here. At least, not if you want to be compatible with bash < 4.0.

With bash 4 we can use co-processes:

coproc ssh user@host 'command & read; kill $!'
trap 'echo >&"${COPROC[1]}"' EXIT
...

Now, when the local script exits (don't trap on INT, TERM, etc. Just EXIT) it sends a new line to the file in the second element of the COPROC array. That file is a pipe which is connected to ssh's stdin, effectively routing our line to ssh. The remote command reads the line, ends the read and kills the command.

Before bash 4 things get a bit harder since we don't have co-processes. In that case, we need to do the piping ourselves:

mkfifo /tmp/mysshcommand
ssh user@host 'command & read; kill $!' < /tmp/mysshcommand &
trap 'echo > /tmp/mysshcommand; rm /tmp/mysshcommand' EXIT

This should work in pretty much any bash version.

这篇关于使用bash在ssh上启动进程,然后在sigint上将其杀死的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆