如何设置SSH超时时间?

271

我正在执行一段通过无密码SSH连接到远程主机的脚本。我想设置一个超时时间,以便如果远程主机花费无限时间来运行,我希望退出该ssh会话并继续我的sh脚本中的其他行。

如何设置超时时间?


这个问题很可能应该被关闭,以使其与一个完全重复的问题如何降低ssh连接超时值[closed]保持一致。 - Murmel
1
如果您只是为了在您的 ssh 会话中停留更长时间而被重定向到此处(问题“如何增加SSH连接超时时间?”),那么这是错误的地方。答案在关于ssh-timeout的此链接中。 - Peter Krauss
8个回答

426
ssh -o ConnectTimeout=10  <hostName>

这里的10代表秒数,超时时间仅适用于连接创建。


7
ConnectTimeout只对连接建立设置超时时间,是吗? - Mmmh mmh
27
对于“远程主机运行时间无限长”的情况,"ssh -o ConnectTimeout=5 host 'sleep 10'" 实际上不起作用:它会等待10秒钟而不是5秒钟。 - Ferry Boender
4
@FerryBoender 看起来 ConnectTimeout 只影响连接。你的例子已经成功连接了。 - laconbass

119

使用 -o ConnectTimeout-o BatchMode=yes -o StrictHostKeyChecking=no 选项。

ConnectTimeout 避免脚本挂起, BatchMode 避免出现“主机未知”问题并添加到 known_hosts,StrictHostKeyChecking 自动添加指纹。

**** 注意 **** "StrictHostKeyChecking" 只适用于您信任的内部网络。根据 SSH 客户端版本,"是否要添加您的指纹" 可能会导致客户端无限期地挂起(主要是在 AIX 上运行的旧版本)。大多数现代版本不会遇到此问题。如果您必须处理多个主机的指纹,请使用像 puppet/ansible/chef/salt 等配置管理工具维护 known_hosts 文件。


26
“-o StrictHostKeyChecking=no” 不仅不能解决问题,而且如果你在乎安全性的话,它是一个可怕的想法,这也可能是你首次使用 SSH 的原因。 - Dolph
10
指出-o StrictHostKeyChecking=no可能存在的安全隐患是有益的。然而,这将防止脚本在执行期间挂起。 - Doug
2
警告!!!正如@Dolph所写,如果您关心安全性,请不要使用StrictHostKeyChecking=no。@Doug:脚本不会挂起-它只会坚持让您手动ssh到远程主机,以便了解主机。但它将保护您免受MITM攻击。请编辑此答案以反映这一点,因为它作为现有的非常危险的建议。而且甚至没有被要求。 - johndodo
2
更新了我的回答。根据我的经验,它可能会导致一些客户端挂起。 - Doug
如果你真的必须这样做,请使用-o StrictHostKeyChecking=accept-new。根据这个答案 - Steven de Salas

74

试试这个:

timeout 5 ssh user@ip

timeout命令在执行带参数的ssh命令后,如果ssh命令5秒钟内没有返回,会发送一个SIGTERM信号。 要了解更多关于timeout命令的信息,请阅读此文档: http://man7.org/linux/man-pages/man1/timeout.1.html

或者你也可以使用ssh的参数:

ssh -o ConnectTimeout=3 user@ip

6
如果您在 Mac 上寻找此命令,请尝试 brew install coreutils,然后使用 gtimeout(来源:https://dev59.com/iXA75IYBdhLWcg3wB0ZP)。 - larcher
5
这个命令可能不会达到你想要的效果。考虑一下命令 timeout 3s ssh user@server 'sleep 5; echo blarg >> /tmp/blarg'。这会终止 SSH 客户端上的进程,但是远程服务器上的 /tmp/blarg 文件仍然会被修改。这意味着,如果你在远程服务器上运行一个耗费大量 CPU 资源的任务,你将会有进程泄漏的风险。 - James Davis
1
@JamieDavis 你觉得 ssh user@server 'timeout 5s sleep 10' 怎么样? - FilipR
@FilipR 如果连接从未建立,这不会超时 ;) - xeruf
“这个还是那个”通常会引发问题:“为什么不两者兼备呢?”我在自己的脚本中使用了两者的组合。timeout $X的阈值应该比ssh -o ConnectTimeout=$Y的阈值更大(即X > Y),这是很自然的。这可以避免当连接成功建立后,远程机器挂起而你无法进入队列中的下一个机器的情况。 - Rich
这应该是根据问题所接受的答案。 - undefined

28

您还可以通过使用标志

-o ServerAliveInterval=<secs>
与服务器建立连接,这样SSH客户端将每隔<secs>秒向服务器发送一个空包,以保持连接。

在Linux系统上,此设置可以全局设置在/etc/ssh/ssh_config中,也可以个人设置在~/.ssh/config中。


7
听起来这似乎与问题要求的相反。 - Davor Cubranic

3

如果所有其他尝试都失败了(包括没有使用 timeout 命令),则此 shell 脚本中的概念将起作用:

 #!/bin/bash
 set -u
 ssh $1 "sleep 10 ; uptime" > /tmp/outputfile 2>&1 & PIDssh=$!
 Count=0
 while test $Count -lt 5 && ps -p $PIDssh > /dev/null
 do
    echo -n .
    sleep 1
    Count=$((Count+1))
 done
 echo ""

 if ps -p $PIDssh > /dev/null
 then
    echo "ssh still running, killing it"
    kill -HUP $PIDssh
 else
    echo "Exited"
 fi

1

只需添加以下我使用的.ssh/config片段,

  ServerAliveInterval 20
  ServerAliveCountMax 5
  ConnectTimeout 10

1
"

timeout 5 ssh user@machine

在我的电脑上运行得很好。"

0

嗯,你可以使用nohup在“非阻塞模式”下运行任何你想运行的东西。这样你就可以不断检查它是否按照预期运行,否则就退出。

nohup ./my-script-that-may-take-long-to-finish.sh &
./check-if-previous-script-ran-or-exit.sh
echo "Script ended on Feb 15, 2011, 9:20AM" > /tmp/done.txt

所以在第二个命令中,你只需要检查文件是否存在即可。


听起来没问题。但是,正在运行的脚本会给我一些输出,这些输出会显示在控制台上...如何检查我的先前脚本是否运行或退出?$?还是其他什么? - user57421
你可以让脚本在完成时创建一个文件。我已经将注释添加到答案中了... 嗷! - Eduardo

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