Automatically (or more easily) reconnect to a screen session after network interruption

ADDED: This question is now, I believe, subsumed by this one: Using GNU Screen completely transparently and automatically

See also this related question:
https://superuser.com/questions/147873/ssh-sessions-in-xterms-freeze-for-many-minutes-whenever-they-disconnect

Original question:

It would be nice if there were a way to ssh to a machine and immediately reconnect to a specific screen session. You can do this:

laptop> ssh server.com screen -ls

and it will show a list of screens available on server.com like so [1]:

123.pts-1
456.pts-2

And then you might try to do this:

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

but that fails, saying "Must be connected to a terminal." You have to ssh in first and then do the "screen -dr pts-2" on server.com which is no good if you have a flaky connection and get disconnected a lot. You want to be able to resume with a simple "up-arrow enter" on the laptop. (Or perhaps make it even more automatic.)

I have a rihackulous solution to this problem which I'll post as an answer and hope it gets downvoted to oblivion in favor of the Right Way to deal with this.


Footnotes:

[1] Or, better, if you created the screen sessions with names like "screen -S foo" and "screen -S bar" then you'll get a friendlier list like:

123.foo
456.bar

and can reconnect with, eg, "screen -dr foo".


Mini screen tutorial, incorporating the answer to this question:

Login in to server.com and do

screen -S foo 

and then never log out of that session again. To reconnect to it from elsewhere, do

ssh -t server.com screen -dr foo

To list available screens to reconect to:

screen -ls

or, of course,

ssh server.com screen -ls

to check on server.com's available screens remotely.

I now use the following alias (tcsh), based on Jason's answer below, to connect to a named screen if it exists or create and connect otherwise:

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

Solution 1:

Does the -t option do what you want?

     -t      Force pseudo-tty allocation.  This can be used to execute arbi-
             trary screen-based programs on a remote machine, which can be
             very useful, e.g. when implementing menu services.  Multiple -t
             options force tty allocation, even if ssh has no local tty.

So:

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

This seems to work in my installation.

Solution 2:

This is now subsumed by this: Using GNU Screen completely transparently and automatically


Here's a script, ssc, that works just like ssh but takes a third argument to specify the screen to reconnect to, or the name of a new screen. I believe this script subsumes everything in the original question.
#!/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\"");
}