DEV Community

Mika Feiler
Mika Feiler

Posted on • Edited on

Want to login to a Bash 5 not in /etc/shells while having your $SHELL, and login shell, set to /bin/bash which stays on v4?

When you run a shell within your login shell, $SHELL is still your login shell. When you run another shell within that shell, $SHELL still stays the same. There are some bad scripts the behavior of which incorrectly depends on $SHELL. If you want to run Bash, you might want $SHELL to stay /bin/bash.

And sometimes you want to login to a version of Bash not from /etc/shells β€” like, from somewhere else in the system or even from your home directory.

I'm not sure if there is any non-shell-specific standard way of getting the path of your childmost shell executable. In Bash you can get it from $BASH.

If you want to land in /bin/bash only if your own bash binary doesn't get found in $PATH, put this in your .bashrc:

(return $NO_FURTHER_PLEASE) && [[ $BASH == "/bin/bash" ]] && { NO_FURTHER_PLEASE=1 bash; exit $?; }
Enter fullscreen mode Exit fullscreen mode

You might want to replace "/bin/bash" for $SHELL in the above if you are not sure if your login shell will stay /bin/bash since $SHELL will be always your login shell from /etc/shells.

If you also want to land in /bin/bash wherever it is already Bash 5 or newer, put this instead:

(return $NO_FURTHER_PLEASE) && [ "${BASH_VERSINFO:-0}" -le 4 ] && { NO_FURTHER_PLEASE=1 bash; exit $?; }
Enter fullscreen mode Exit fullscreen mode

Note that in both cases if the bash from $PATH ends up being /bin/bash, you get /bin/bash inside /bin/bash. That could be improved on by re-checking against the original condition with something like

((return $NO_FURTHER_PLEASE) || [ the condition goes there ]) && (exit 2)
Enter fullscreen mode Exit fullscreen mode

or instead, even better,

(return $NO_FURTHER_PLEASE) && [[ $SHELL == $BASH ]] && (exit 2)
Enter fullscreen mode Exit fullscreen mode

Of course, one could just hardcode the absolute path of their bash in .bashrc and then there would be no such problem.

If someone is wondering, no, $NO_FURTHER_PLEASE is not inherited by any bash that you choose to run inside your bash since NO_FURTHER_PLEASE is not exported.

Yes yes i know that there is probably a neater way to test against a variable than returning it from a subshell, i am just too lazy to look for it.

Edit

It seems like all of the above could be replaced with just

FURTHER_BASH=$(type -p bash)
if [[ $SHELL != $BASH ]]
then
    unset FURTHER_BASH
elif [[ $BASH != $FURTHER_BASH ]]
then 
    $FURTHER_BASH
    exit $?
else
    unset FURTHER_BASH
    echo "Staying in login shell." >&2
fi
[ "${BASH_VERSINFO:-0}" -le 4 ] && {
    echo "Warning: Staying in bash version $BASH_VERSINFO < 5."
    (exit 2)
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)