网络中断后自动(或更轻松地)重新连接到屏幕会话

57

补充说明:我相信这个问题现在已经被这个问题所包含: 如何完全透明而自动地使用GNU Screen

还可以参考以下相关问题:
https://superuser.com/questions/147873/ssh-sessions-in-xterms-freeze-for-many-minutes-whenever-they-disconnect

原始问题:

如果有一种方法可以通过ssh连接到一个机器并立即重新连接到特定的screen会话,那将是很好的。你可以这样做:

laptop> ssh server.com screen -ls

这会显示一个可用于 server.com 上的屏幕列表,如下所示 [1]:

123.pts-1
456.pts-2

然后,您可以尝试这样做:

laptop> ssh server.com screen -dr pts-2

但是这样会失败,并显示“必须连接到终端”。
您必须先通过ssh访问服务器,然后执行“screen -dr pts-2”,如果连接不稳定经常断开,则无法做到这一点。 您希望能够使用简单的“上箭头 回车”在笔记本电脑上恢复(或者更加自动化)。
我有一个神奇的解决方案,我将它发布为答案,并希望它被否决,以支持正确的解决方案。
注释:
[1] 或者更好的方法是,如果您像 "screen -S foo" 和 "screen -S bar " 这样命名了 screen 会话,那么您将得到一个更友好的列表:
123.foo
456.bar

你可以使用例如 "screen -dr foo" 来重新连接。


小屏幕教程,包含此问题的答案:

登录到 server.com 并执行

screen -S foo 

然后再也不要退出该会话。要从其他地方重新连接到它,请执行以下操作

ssh -t server.com screen -dr foo

列出可重连的屏幕:
screen -ls

当然,或者说:

ssh server.com screen -ls

远程检查server.com上可用的屏幕。

我现在使用以下别名(tcsh),基于下面Jason的回答,如果存在,则连接到命名屏幕,否则创建并连接:

alias ssc 'ssh -t \!:1 "screen -S \!:2 -dr || screen -S \!:2"'
6个回答

62

你是否需要使用-t选项?

     -t      强制分配伪终端。这可以用于在远程机器上执行任意基于屏幕的程序,非常有用,例如实现菜单服务。多个-t选项强制分配tty,即使ssh没有本地tty。

所以:

laptop> ssh -t server.com screen -dr pts-2

在我的安装中似乎可以正常工作。


6
天啊,我简直不敢相信它竟然如此简单!实际上,我几年前就想到了下面这个怪物般的东西。我会告诉自己这是在“-t”选项出现之前就存在了 :) 非常感谢你给出真正的答案! - dreeves

4

现在可以使用GNU Screen 完全透明和自动化地使用,这已经包含了以前的内容。


这里提供了一个名为ssc的脚本,它的功能类似于ssh,但是需要第三个参数来指定要重新连接到的屏幕或新屏幕的名称。我认为这个脚本包括了原问题中的所有内容。

#!/usr/bin/env perl
# Use 'ssc' (this script) instead of 'ssh' to log into a remote machine.
# Without a 3rd argument it will list available screens.
# Give it a 3rd argument to attach to an existing screen or specify a new
#   screen.  Eg, ssc remote.com foo
# The numbers in front of the screen tag can usually be ignored.
# Screen is a little too clever though in that if there's an existing screen "bar"
#   and you say "ssc remote.com b" it will reconnect you to "bar" instead of making
#   a new screen "b".  It's like invisible and silent tab-completion.

if(scalar(@ARGV)==0 || scalar(@ARGV) > 2) {
  print "USAGE: ssc remote.com [screen name]\n";
} elsif (scalar(@ARGV) == 1) {
  $machine = shift;
  @screens = split("\n", `ssh $machine screen -ls`);
  for(@screens) {
    if(/^\s*(\d+)\.(\S+)\s+\(([^\)]*)\)/) {
      ($num, $tag, $status) = ($1, $2, $3);
      if($status =~ /attached/i) { $att{"$num.$tag"} = 1; }
      elsif($status =~ /detached/i) { $att{"$num.$tag"} = 0; }
      else { print "Couldn't parse this: $_\n"; }
    }
  }
  print "ATTACHED screens:\n";
  for(keys(%att)) { print "  $_\n" if $att{$_}; }
  print "DETACHED screens:\n";
  for(keys(%att)) { print "  $_\n" unless $att{$_}; }
} else {
  $machine = shift;
  $tag = shift;
  system("ssh -t $machine \"screen -S $tag -dr || screen -S $tag\"");
}

不错的脚本,在 https://gist.github.com/gretel/c2ef247f51e3cf0c654e 上进行了改进 - 谢谢! - jitter
1
小调整:在某个时刻,当运行 screen -ls 时,屏幕开始显示日期,因此 正则表达式需要进行一些调整以适应这种情况 - Ryan Lewis

3

我一直在研究类似的东西,但还没有完全实现,你的解决方案解决了我的问题,所以这是我的建议:

ssh -t server.com "screen -S foo -rd || screen -S foo"

这段代码尝试打开名为foo的现有屏幕,如果不存在则创建它。 我会把它放在我的笔记本电脑上的启动器中,这样当无线网络断开时,我可以继续上次的工作。

刚刚注意到默认的屏幕Shell有点弱,所以一个改进是设置你的主目录环境:

ssh -t server.com "screen -S foo -rd || screen -S foo bash -l"

2

使用-t选项ssh连接时,可以在直接运行命令的同时分配终端。

laptop> ssh -t server.com screen -dr pts-2

1
如果您希望始终连接到同一个会话,即使它是活动的、分离的或尚不存在,请使用以下命令:

ssh -t user@server screen -xR screenName

如果在其他pty上已经存在相同的会话,则创建一个新会话,可以使用以下命令:

ssh -t user@server screen -rR screenName


1
我将其修改,使其适用于OS X的.bash_profile,并进行了一项添加:如果没有给出第二个参数,则会启动一个名为"default"的会话。
function ssc() {
    if [[ -z $2 ]]; then
        screen="default"
    else
        screen=$2
    fi
    ssh -t $1 "screen -S $screen -dr || screen -S $screen"
}

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