如何使用ssh在后台运行命令并分离会话

24

我目前正在尝试使用ssh登录到远程机器并运行脚本,然后退出拥有脚本运行的节点。以下是我的脚本。但是当它运行时,脚本在机器上成功运行,但ssh会话挂起。问题出在哪里?

ssh -x $username@$node 'rm -rf statuslist
                        mkdir statuslist
                        chmod u+x ~/monitor/concat.sh
                        chmod u+x ~/monitor/script.sh
                        nohup ./monitor/concat.sh &
                        exit;'
5个回答

27

有一些情况下,你想在远程机器/服务器上执行/启动一些脚本(这些脚本将自动终止)并断开与服务器的连接。

例如:在一个盒子上运行的脚本,在执行时:

  1. 将一个模型复制到远程服务器
  2. 创建一个用于在服务器上运行模拟的脚本并将其推送到服务器
  3. 在服务器上启动该脚本并断开连接
  4. 已启动的脚本的职责是在服务器上运行模拟,一旦完成(需要几天时间),将结果复制回客户端。

我会使用以下命令:

ssh remoteserver 'nohup /path/to/script `</dev/null` >nohup.out 2>&1 &'

@CKeven,您可以将所有这些命令放在一个脚本中,将其推送到远程服务器,并按以下方式启动:

echo '#!/bin/bash  
rm -rf statuslist  
mkdir statuslist  
chmod u+x ~/monitor/concat.sh  
chmod u+x ~/monitor/script.sh  
nohup ./monitor/concat.sh &  
' > script.sh

chmod u+x script.sh

rsync -azvp script.sh remotehost:/tmp

ssh remotehost '/tmp/script.sh `</dev/null` >nohup.out 2>&1 &'
希望这个能够正常工作 ;-)
编辑: 你也可以使用 ssh user@host 'screen -S SessionName -d -m "/path/to/executable"' 它会创建一个独立的 screen 会话,并在其中运行目标命令。

如果你运行的命令需要从文件中获取输入(例如大型数据库导入,如mysql < dump.sql),该怎么办?如果你需要将文件重定向到/dev/null,该如何实现? - cayblood
如果您监控ps -ef | grep ssh,这个进程会一直运行。如果我使用-9杀死它,远程进程仍然会继续运行。有没有办法让本地不保持这个进程在运行状态,只保留远程的运行。我已经尝试删除> nohup.out但是它会将输出重定向到标准输出。有什么建议吗? - NiharGht

22
你认为使用screen怎么样?你可以通过ssh运行screen来启动命令(concat.sh),然后如果你想监视它,就可以返回到屏幕会话中(这可能很方便,具体取决于concat的功能)。
更具体地说,请尝试以下操作:
ssh -t $username@$node screen -dm -S testing ./monitor/concat.sh

您应该会发现提示符立即返回,而concat.sh正在远程计算机上运行。以下是一些选项的解释:
  • ssh -t 创建一个TTY终端,screen需要它。
  • screen -dm 以“分离”模式启动。对于您的目的来说,这就像是“后台”。
  • -S testing 为您的屏幕会话命名。它是可选的,但建议使用。
现在,一旦您完成了这个步骤,您可以去远程计算机并运行以下命令:
screen -r testing

这将使您附加到包含程序的屏幕会话中。从那里,您可以控制它、终止它、查看其输出等等。按下Ctrl-A,然后再按d键即可将您从屏幕会话中分离出来。screen -ls会列出所有正在运行的会话。


2
@John Zwinck,这对您确实有效吗?以下命令对我无效:ssh -t HOST "screen -dm -S sleep sleep 10"。它只是显示“连接到HOST关闭”,当我登录服务器时没有分离的屏幕。 - richardkmiller
4
我刚试了一下,得到了和你一样(不好的)的结果。我将SSH的-t选项改为-f,这样它会将命令放到后台执行(而不会分配TTY),然后它就可以工作了。我怀疑在我回答这个问题的2年多以来,Linux发生了一些变化……尝试使用 ssh -f HOST "screen -dm -S sleep sleep 10",你可能会发现它现在能够工作了。 - John Zwinck

4
这可能是标准输入流。尝试使用ssh -n ...ssh -f ...

好的。谢谢。ssh -f "user@host DISPLAY=myhost:0.0 qtcreator &" - kyb

0

下面是一个更加普遍的决策,需要一些努力才能找到,并且它真的对我有效:

#!/usr/bin/bash
theScreenSessionName="test"
theTabNumber="1"
theStuff="date; hostname; cd /usr/local; pwd; /usr/local/bin/top"

echo "this is a test"

ssh -f user@server "/usr/local/bin/screen -x $theScreenSessionName -p $theTabNumber -X stuff \" 
$theStuff
\""

它将$theStuff命令列表发送到屏幕会话$theScreenSessionName的选项卡号$theTabNumber,该会话最初是代表“用户”在“服务器”上创建的。

请注意,在“-X stuff \”之后有一个尾随空格,以克服“stuff”选项的故障。下一行中的空格和$theStuff由“Enter” (^M)按键附加。不要错过它们!

“这是一个测试”消息在初始终端中回显,并且$theStuff命令确实在所提到的屏幕/选项卡内执行。


0

对我来说,只有这个有效:

screen -dmS name sh my-script.sh

当然,这取决于屏幕,如果您需要stdin或stdout,您可以稍后附加。当my-script.sh结束时,屏幕将自行终止。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接