scriptingautomationsshgnu-screen

Using GNU Screen completely transparently and automatically


Screen is amazing, of course, but I don't want to have to think about it. I often ssh to a machine, start doing a bunch of stuff, and then think "gosh, I wish I had thought to start a screen session before doing all that so I could reconnect to this from home later".

I'd like to have screen automatically started whenever I log in to a machine. And when I get disconnected, I want to be able to immediately and simply reconnect without fussing with "screen -ls" and "screen -dr".

I have a script that implements one solution to this problem which I'll post as an answer. I'm interested to see other approaches.


Solution

  • Use the following, ssc, instead of ssh. If you just do "ssc remote.com" then it will list existing screen sessions. Give it a 3rd argument and it will connect to that screen session, or create it and connect to it. Either way, if you get disconnected you can just do "up-arrow, enter" in the shell to reconnect. Zero knowledge of screen required! Edit: Thanks to @klochner for extending this to handle arbitrary ssh options. You can now use this just like ssh!

    #!/usr/bin/env perl
    # Use 'ssc' (this script) instead of 'ssh' to log into a remote machine.
    # Without an argument after the hostname it will list available screens.
    # Add an argument after the hostname 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.
    
    # ssh option parsing by @klochner
    my $optstring = ""; 
    while ($val = shift) {
      if    ($val =~ /^-\w$/)  { $optstring .= " ".$val.(shift); }
      elsif ($val =~ /^-\w+$/) { $optstring .= " ".$val;         }
      elsif ($machine)         { $tag        =     $val;         }
      else                     { $machine    =     $val;         }
    }
    
    if (!$machine) {
      print "USAGE: ssc [ssh options] remote.com [screen name]\n";
    } elsif (!$tag) {
      @screens = split("\n", `ssh $optstring $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"; }
          # remember anything weird about the screen, like shared screens
          if($status =~ /^(attached|detached)$/i) { 
            $special{"$num.$tag"} = "";
          } else {
            $special{"$num.$tag"} = "[$status]";
          }
        }
      }
      print "ATTACHED:\n";
      for(sort { ($a=~/\.(\w+)/)[0] cmp ($b=~/\.(\w+)/)[0] } keys(%att)) {
        ($tag) = /\.(\w+)/;
        print "  $tag\t($_)\t$special{$_}\n" if $att{$_};
      }
      print "DETACHED:\n";
      for(sort { ($a=~/\.(\w+)/)[0] cmp ($b=~/\.(\w+)/)[0] } keys(%att)) {
        ($tag) = /\.(\w+)/;
        print "  $tag\t($_)\t$special{$_}\n" unless $att{$_};
      }
    } else {
     system("ssh $optstring -t $machine \"screen -S $tag -dr || screen -S $tag\"");
    }
    

    Btw, there's a trick to forcing an ssh session to exit and give you back your local terminal prompt when you lose network connectivity:
    https://superuser.com/questions/147873/ssh-sessions-in-xterms-freeze-for-many-minutes-whenever-they-disconnect