14

Currently I use Fish as my main shell on local and remote hosts.

I connect to remote hosts via ssh and sftp. I wanted to open or reuse a remote tmux whenever I connect, automatically, by default; so I added this to my ~/.ssh/config:

Host example.com
RemoteCommand tmux a; or tmux
RequestTTY yes

The problem is that now I cannot connect through sftp, nor can I run a direct command from my local CLI:

➤ ssh example.com ping localhost
Cannot execute command-line and remote command.

➤ sftp example.com
Cannot execute command-line and remote command.
Connection closed

So, my question is: How can I define a default command to be executed when opening a new interactive SSH session, but make it overridable?

9

Option 1 )

You can the option Match ( see man ssh_config )

Match Host example.com exec "test $_ = /usr/bin/ssh"
     RemoteCommand tmux a; or tmux
     RequestTTY yes

This will only differentiate difference between ssh & sftp

Option 2

You create some placeholder config for your diffe command , example :

Host tmux.example.com
  HostName example.com
  HostKeyAlias example.com
  RemoteCommand tmux a; or tmux
  RequestTTY yes

And after you can still use example.com for you sftp / ping usage .

4
  • 1st option didn't work. It seems Fish doesn't export $_. However, I can manually export a variable with set -x auto_tmux 1 and change the match test to "[ 1 -eq $auto_tmux ]"
    – Yajo
    Jun 25 '18 at 9:04
  • 7
    Thanks, this helped me find an answer that worked for me: change the match to Match exec "[[ $(ps h o args p $PPID | wc -w) -eq 2 ]]". That exec is true when ssh is invoked as "ssh <server>" but false if invoked as, say, "ssh <server> <command>"
    – cryptarch
    Nov 14 '18 at 6:56
  • if you have multiple hostnames nomrally space-separated like Host with.example.com multiple.example.com and you wish to use Match this way, try curly braces: Match Host {with.example.com,multiple.example.com} exec "..."
    – rymo
    Dec 3 '19 at 23:08
  • @rymo, I wasn't able to get that working with OpenSSH 8.0p1, dated 2019-05-28. Wasn't able to find any way to match on multiple hostnames with that version, except by adding it to the exec portion: Match exec "[[ %n == @(pihole|router|athena|nas) && $(ps h o args p $PPID | wc -w) -eq 2 ]]".
    – Head Geek
    Jan 3 '20 at 16:36
4

I'm using something more complex that deals with ssh options and space in arguments:

Match exec "POSIXLY_CORRECT=1 xargs -0 getopt -o 46AaCfGgKkMNnqsTtVvXxYyB:b:c:D:E:e:F:I:i:J:L:l:m:O:o:p:Q:R:S:W:w: --  </proc/$PPID/cmdline | perl -pe 's|.*? -- ||' | { read -r c; eval a=($c); [ ${#a[@]} -le 2 ]; }"
    RemoteCommand my-command-here
    RequestTTY yes

Also, if someone wants to use RemoteCommand for some machines (like inside "host xxxx"), the same trick can be used in reverse logic (match are evaluated after host):

Match exec "POSIXLY_CORRECT=1 xargs -0 getopt -o 46AaCfGgKkMNnqsTtVvXxYyB:b:c:D:E:e:F:I:i:J:L:l:m:O:o:p:Q:R:S:W:w: -- </proc/$PPID/cmdline | perl -pe 's|.*? -- ||' | { read -r c; eval a=($c); [ ${#a[@]} -gt 2 ]; }"
     RemoteCommand none
     RequestTTY auto

Host machine1 machine2 ...
     RemoteCommand my-command-here
     RequestTTY yes

If someone is curious, I'm currently using RemoteCommand to call screen:

RemoteCommand which screen &>/dev/null && TERM=xterm screen -q -RR "%u-%C" $SHELL -l || $SHELL -l
5
  • 1
    What's that supposed to do?
    – Yajo
    Feb 10 '19 at 7:07
  • Parses ssh args in a space/quotes-safe manner, ignores any valid ssh opt (including opt value when required) and count if the remaining args are only two ("ssh" and "host"). It's similar to @cryptarch solution but also considering extra ssh opts. Feb 11 '19 at 10:51
  • 1
    Ssh could save us some pain if it simply consider command in cmdline to have higher precedence than -o RemoteCommend Feb 11 '19 at 10:59
  • This doesn't work with Fish, my main shell, as explained in the question :/
    – Yajo
    Feb 11 '19 at 11:06
  • You can add "| tee /dev/stderr" before "perl" to check what it outputs. It might need a new kind of filter Feb 13 '19 at 18:42
0

One option would be to make a symlink alias to the ssh command:

ln -s /usr/bin/ssh $HOME/bin/ssht

To make life easier, make sure $HOME/bin is in your $PATH.

In your ssh config:

Match Host example.com exec "test $_ = $HOME/bin/ssht"
     RemoteCommand tmux new-session -A -s mysession
     RequestTTY yes

Now, you can choose to use ssht example.com or ssh example.com for tmux and non-tmux sessions, respectively.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.