views:

851

answers:

7

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.

+2  A: 

Depends on your shell, but what about .bashrc? (If you use bash "screen -rd")

EFraim
The reason behind downvote is: some one dislikes bash?
EFraim
+8  A: 

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:
http://superuser.com/questions/147873/ssh-sessions-in-xterms-freeze-for-many-minutes-whenever-they-disconnect

dreeves
As to screen being too clever with its invisible and silent tab-completion on the screen names, I suggest a convention of making sure every screen name you use start with a distinct letter. Use a descriptive word the first time but from then on you can use just the first letter.
dreeves
+1  A: 

Maybe put "exec screen -dr" in your .login?

Geoff Fritz
+4  A: 

I have the following in my .bashrc

 if [ "$PS1" != "" -a "${_STARTED_SCREEN:-x}" = x -a "${SSH_TTY:-x}" ] 
 then 
     export _STARTED_SCREEN=1;
     sleep 1 
     screen -RR && exit 0 
     # normally, execution of this rc script ends here... 
     echo "Screen failed! continuing with normal bash startup" 
 fi

I found it online somewhere awhile ago, not sure where.

Update Fixed error that was pointed out in comments. Thanks R. Pate

seth
Isn't "export _STARTED_SCREEN=1" enough, instead of setting then exporting?
Roger Pate
+1  A: 

Actually screen sets the TERM variable to 'screen'. So the script is even easier. Here is what I use:

if [ "$TERM" != "screen" ]; then
  screen -xRR
fi

Works like a charm, the -x ensures that even if the screen is attached somewhere else I attach to it here. This way I only every have one screen where I can keep track of everything.

Feanil
What if the user runs "ssh hostname 'ls -R ~/.local'", for example?
Sridhar Ratnakumar
+3  A: 

there is autossh which automatically reconnects disconnected ssh-sessions.

It comes with an example script called rscreen which does exactly that. It is, simply:

#!/bin/sh
autossh -M 0 -t $1 "screen -e^Aa -D -R"

Then you have to retrain your fingers to type rscreen hostname instead of ssh hostname

levinalex
+1  A: 

i have used autossh, it is very useful to me

overlord