Bash – Issues with scp if I use bashrc to open fish if present

bashbashrcfishscp

Situation: Need to login to multiple remote servers with some of them having fish shell

Requirement: Default shell is bash. If I login to a server and fish is present, switch to fish shell, otherwise stay on bash.

Tried .bashrc:

# .bashrc

# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi

# Source global definitions
if [ -f /etc/bash.bashrc ]; then
        . /etc/bash.bashrc
fi

# Update Path
export PATH=/sbin:/usr/sbin:/usr/local/sbin:$PATH:$HOME/.bin

# Open fish shell if present, otherwise stick to bash
if hash fish 2>/dev/null; then
        # echo "Fish detected, shifting shell"
        fish "$@"; exit
fi

However, scp doesn't seem to be working. When I try to scp a file, verbose output shows it to be stuck here.

debug1: Authentication succeeded (publickey).
debug1: channel 0: new [client-session]
debug1: Requesting no-more-sessions@openssh.com
debug1: Entering interactive session.
debug1: pledge: network
debug1: client_input_global_request: rtype hostkeys-00@openssh.com want_reply 0
debug1: Sending environment.
debug1: Sending env LANG = en_US.UTF-8
debug1: Sending env LC_ADDRESS = en_US.UTF-8
debug1: Sending env LC_IDENTIFICATION = en_US.UTF-8
debug1: Sending env LC_MEASUREMENT = en_US.UTF-8
debug1: Sending env LC_MONETARY = en_US.UTF-8
debug1: Sending env LC_NAME = en_US.UTF-8
debug1: Sending env LC_NUMERIC = en_US.UTF-8
debug1: Sending env LC_PAPER = en_US.UTF-8
debug1: Sending env LC_TELEPHONE = en_US.UTF-8
debug1: Sending env LC_TIME = en_US.UTF-8
debug1: Sending command: scp -v -f test_file

Initially I thought the echo command was causing it to not work, but it doesn't work without it as well.

Best Answer

To exit the bashrc file when the shell session that is sourcing it is not interactive, you may do the following at the top (or in a convenient location) of the file:

case "$-" in
    *i*)        ;;
    *)   return ;;
esac

The value in $- is a string of letters denoting the currently set shell options. If the i character is present in the string, then the shell is interactive.

This may be needed since, as terdon pointed out in comments, Bash treats shell sessions that are started by sshd, the SSH daemon, as a special case.

Details: Why does bashrc check whether the current shell is interactive?

Further down in the file, you may check whether the fish shell is available and start that:

if command -v fish 2>/dev/null; then
   exec fish
fi

Be aware that fish may be the game of "Go Fish" on some systems :-)

About the use of command -v: Why not use "which"? What to use then?

Related Question