I'm quite often doing stuff on remote machines, and quite frequently I start some long-running job, when I remember that I didn't ran it via screen – so it will break, if my network connection will die.
Is there any sane way to start screen automatically? YES.
In manual to screen, you can find that you can simply put screen as your shell in /etc/passwd. Which is true, but it has problems. Namely:
- You no longer can scp anything to the machine using this account
- You no longer can su – name to this account
Why? It looks like this:
=$ scp test.file test@localhost: Must be connected to a terminal.
And via su:
=# su - test Cannot open your terminal '/dev/pts/9' - please check.
Which kinda sucks.
So I started digging for better option.
Finally I added these lines to the end of my ~/.bash_profile (not bashrc!):
if [[ ( -z "$STY" ) && ( ! -z "$SSH_CONNECTION" ) ]] then exec screen -R -D -S shell fi
Which kinda-works, but the “kinda" is actually problematic:
- it will not work with multiplexed ssh connections
- if I will run ssh to the same account from single place, it will close earlier connection
- when starting first shell (i.e. not re-attaching) it shows annoying notification, which cannot be disabled (i.e. I can disable all notifications, but then I will also hide all other. And it makes shell startup delayed.
After some more tinkering I finally found nearly perfect solution:
if [[ ( -z "$STY" ) && ( ! -z "$SSH_CONNECTION" ) ]] then screen -S shell -x 2> /dev/null || screen -S shell logout fi
Which is actually pretty cool – “su –" works (doesn't start screen), scp works, I can use multiplexing, and previous sessions are not detached on new connect (they all share the same screen session).
The only problem with this approach is that it leaves behind one obsolete bash process:
test@h3po4:~$ ps uxf USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND test 21927 0.0 0.0 85424 2016 ? S 13:48 0:00 sshd: test@pts/7 test 21928 0.0 0.0 19288 1932 pts/7 Ss+ 13:48 0:00 \_ -bash test 21932 0.0 0.0 25168 1276 pts/7 S+ 13:48 0:00 \_ screen -S shell test 21933 0.0 0.0 25728 1756 ? Ss 13:48 0:00 \_ SCREEN -S shell test 21934 0.0 0.0 19412 2192 pts/10 Ss 13:48 0:00 \_ -bash test 22034 0.0 0.0 15252 1160 pts/10 R+ 13:50 0:00 \_ ps uxf
i.e. bash with PID 21928 is obsolete, and could simply not exist, but it's not possible to get rid of it. Or is it?
Let's add some more logic:
if [[ ( -z "$STY" ) && ( ! -z "$SSH_CONNECTION" ) ]] then COUNT="$( LC_ALL=C LANG=C screen -S shell -ls | grep -cE '[^[:space:]]' )" if [[ "$COUNT" -lt 3 ]] then exec screen -S shell fi exec screen -S shell -xRR fi
With this, after logging to the account I get only these processes:
test@h3po4:~$ ps uxf USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND test 23080 0.0 0.0 85424 1920 ? S 14:00 0:00 sshd: test@pts/10 test 23081 1.0 0.0 25168 1272 pts/10 Ss+ 14:00 0:00 \_ screen -S shell test 23088 0.0 0.0 25596 1696 ? Ss 14:00 0:00 \_ SCREEN -S shell test 23089 0.0 0.0 19416 2164 pts/12 Ss 14:00 0:00 \_ -bash test 23092 0.0 0.0 15252 1160 pts/12 R+ 14:00 0:00 \_ ps uxf
All other stuff works well. There is only one possible issue – what will happen in case of dead screen sessions – well, I didn't put any code for handling it in the bash_profile, as – if something like this would happen – I can always “ssh -t user@server bash" – thus bypassing .bash_profile, and fix the problem manually.