Using GNU Screen completely transparently and auto

2019-01-30 12:47发布

问题:

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.

回答1:

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



回答2:

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



回答3:

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.



回答4:

ssh user@host.com -t 'screen -dRR'

This will reload/create your screen session on connect. This does exactly what was requested, even if it moves the responsibility for spawning the session to the initiating client. Ideally you would want some process on the server managing what gets presented to connecting clients. As far as I know that doesn't exist. No one has suggested the ideal solution in this thread. For me this is less "not ideal" than the rest. No scripts, no bugs, no TTY issues, no bad interactions with other ssh commands, no potential for infinite loops, no file editing, no additional packages required.



回答5:

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



回答6:

i have used autossh, it is very useful to me



回答7:

Maybe put exec screen -dr in your .login?



回答8:

I use mosh (mobile shell). It keeps your connection on even if you go to sleep mode, disconnect from the network, change IP, and so on. Whenever you return, you get your connection back.



回答9:

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