由bash脚本执行的终止SSH会话。
问题:通过bash脚本执行的SSH会话终止的原因是什么?如何解决这个问题?
原因:
当在调用ssh时使用here document来重定向远程主机的stdin,而没有明确指定命令时,会出现以下消息:“Pseudo-terminal will not be allocated because stdin is not a terminal.”(伪终端将不会分配,因为stdin不是终端)。
为了避免这个消息,可以使用ssh的-T选项告诉远程主机不需要分配伪终端,或者明确指定一个命令(如/bin/sh)供远程主机执行here document中的命令。
解决方法:
如果有命令期望stdin / stdout是终端(如top或vim),或者需要在ssh客户端命令执行完成后杀死远程shell及其子进程,则通常应使用ssh -t或者ssh -t -t。详细信息可参考:ssh command unexpectedly continues on other system after ssh terminates。
据我所知,将不分配伪终端的ssh命令和将写入nohup.out的nohup命令结合的唯一方法是让nohup命令在ssh机制未创建的伪终端中执行。例如,可以使用script命令来实现,并且可以避免tcgetattr: Inappropriate ioctl for device的消息。
以下是一个示例脚本,演示了上述解决方法:
#!/bin/bash ssh localhost /bin/sh <<EOF #0<&- script -q /dev/null nohup sleep 10 1>&- & #0<&- script -q -c "nohup sh -c 'date; sleep 10 1>&- &'" /dev/null # Linux 0<&- script -q /dev/null nohup sh -c 'date; sleep 10 1>&- &' # FreeBSD, Mac OS X cat nohup.out exit 0 EOF echo 'done' exit 0
以上是关于解决通过bash脚本执行的SSH会话终止的原因和解决方法的说明。通过使用ssh的-T选项或明确指定命令,可以避免伪终端分配的问题,并且可以使用script命令来执行nohup命令,避免出现tcgetattr: Inappropriate ioctl for device的消息。
问题可能是因为ssh在遵守POSIX标准时,如果仍然有进程附加到tty上,则不会关闭会话。
因此,解决方法可能是将nohup命令的stdin与tty分离:
nohup /path/to/run.sh
另一种方法可能是使用ssh -t -t来强制伪tty分配,即使stdin不是终端。
谢谢。第一种方法没有起作用,与之前的结果相同。-t -t确实起作用,但会出现错误"tcgetattr:对设备的ioctl不合适",考虑到双重-t的作用,这是有道理的。我搜索了一下如何去除错误(我宁愿尽可能地进行清理),但在heredoc中无法找到如何做到。事实证明,Martin Clayton的答案解决了这个问题,所以我将其留在那里。
问题的原因是nohup在通过ssh登录时无法重定向输出,它只有在认为自己连接到终端时才会重定向到nohup.out,而且即使使用了-t参数,你所使用的stdin覆盖也会阻止重定向。
解决方法是自己重定向输出,这样ssh客户端可以断开连接,而不必等待流关闭。可以尝试像下面这样操作:
nohup /path/to/run.sh > run.log &
(这在我从OS X客户端连接到Ubuntu服务器的简单测试中有效。)
非常感谢,这个方法很好用。我之前尝试过从/dev/null重定向输入,但没有想到尝试重定向输出!(我已经测试过将输出重定向到/dev/null也是可行的,即nohup /path/to/run.sh > /dev/null &)
我遇到了一个类似的问题。我正在从一个csh脚本中通过ssh登录,运行远程命令,并试图将输出发送回csh脚本中的一个变量。你认为这可能行得通吗?我遇到了相同的错误:我使用了ssh -t -t并得到了错误消息:Inappropriate IOCtl for device。