Linux – screen -R not working with ssh

gnu-screenlinuxssh

I have a linux box in the office I want to ssh into from my Macbook at home. I can’t reach the box directly on port 22, but I have a port tunnel nailed up between localhost:23001 and port 22 on the remote linux box. This works for a regular ssh session:

$ ssh -t -2 -A -p 23001 roysmith@127.0.0.1

The next step is, I want to automatically run my terminal session inside a screen session. It almost works to do:

$ ssh -t -2 -A -p 23001 roysmith@127.0.0.1  screen -R

If I don’t have a current screen session, it creates one. If there’s already a detached screen, it connects to it. So far, so good. But, the problem is, I never get a login shell, so my .profile never gets run and my environment doesn’t get set up. So, I went one step further, and tried:

$ ssh -t -2 -A -p 23001 roysmith@127.0.0.1  bash -l -c screen -R

Now, I get a real login shell which runs .profile, but screen fails to re-attach to a detached session. I run the above command on my Macbook, and on the remote machine, I’ve got an attached screen:

$ screen -list
There is a screen on:
    21117.pts-21.roysmith01 (01/19/2015 01:50:59 PM)    (Attached)
1 Socket in /var/run/screen/S-roysmith.

If I close the window where I ran the above ssh line, the session gets detached, as expected:

$ screen -list
There is a screen on:
    21117.pts-21.roysmith01 (01/19/2015 01:50:59 PM)    (Detached)
1 Socket in /var/run/screen/S-roysmith.

Now, if I open another local terminal window and run that ssh command again, screen fails to find the detached session and creates a new one:

$ screen -list
There are screens on:
    21304.pts-21.roysmith01 (01/19/2015 01:52:40 PM)    (Attached)
    21117.pts-21.roysmith01 (01/19/2015 01:50:59 PM)    (Detached)
2 Sockets in /var/run/screen/S-roysmith.

Any idea what’s going on here? Why does inserting a login shell keep screen from locating existing sessions?

Best Answer

If there is no existing session to connect to, screen will use whatever command you give after the -R flag. So this should do what you want (without having to touch .screenrc):

$ ssh [...]@127.0.0.1 screen -R bash -l

(This is surely the simplest way to do what you originally set out to do.)

But since you asked, I'll also mention why your bash -l approach didn't work. It was so close!

bash -c takes only the very next argument as a command. Arguments after that go into $0, $1, etc.

$ bash -c echo bar
[just a blank line]
$ bash -c 'echo foo'
foo
$ bash -c 'echo $1' foo bar baz
bar

This does what you wanted bash -l -c screen -R to do:

$ ssh [...]@127.0.0.1 bash -l -c "'screen -R'"

Yes, excitingly you do need two levels of quoting for that to work: the outer quotes tell your local shell to preserve the inner quotes, and the inner quotes are needed because ssh sends the resulting command, bash -l -c 'screen -R', as a string with four spaces in it, not as a list of four words. With one level of quotes, the remote shell would still see bash -l -c screen -R.

This would do it too, with the remote shell being given the command string bash -l -c screen\ -R:

$ ssh [...]@127.0.0.1 bash -l -c 'screen\ -R'

Or this, to give the remote shell bash -l -c "screen -R":

$ ssh [...]@127.0.0.1 bash -l -c \"screen -R\"