Unix & Linux
bash shell-script posix portability
Updated Sun, 17 Jul 2022 12:18:27 GMT

checkbashisms-compliant way to determine the current shell


In my .profile, I use the following code to ensure that Bash-related aliases and functions are only sourced if the login shell actually is Bash:

# If the current (login) shell is Bash, then
if [ "${BASH_VERSION:-}" ]; then
  # source ~/.bashrc if it exists.
  if [ -f "$HOME/.bashrc" ]; then
    . "$HOME/.bashrc"
  fi
fi

Im currently in the process of putting my shell configuration files, scripts and functions under version control. Ive also recently started the process of removing casual Bashisms from shell scripts that dont benefit from Bash-specific features, e.g., replacing function funcname() with funcname().

For my shell files repository, Ive configured a pre-commit hook that runs the checkbashisms utility from Debians devscripts package on each sh file in the repository to ensure that I dont inadvertently introduce Bash-specific syntax. However, this raises an error for my .profile:

possible bashism in .profile line 51 ($BASH_SOMETHING):
if [ "${BASH_VERSION:-}" ]; then

I was wondering if there was a way to check which shell is running that wouldnt trigger a warning in checkbashisms.

I checked the list of shell-related variables listed by POSIX in the hope that one of them could used to show the current shell. Ive also looked at the variables set in an interactive Dash shell but, again, failed to find a suitable candidate.

At the moment, Ive excluded .profile from being processed by checkbashisms; its a small file so its not hard to check it manually. However, having researched the issue, Id still like to know if there is a POSIX compliant method to determine which shell is running (or at least a way that doesnt cause checkbashisms to fail).


Further background/clarification

One of the reasons Im putting my shell configuration files under version control is to configure my environment on all the systems I currently log in to on a regular basis: Cygwin, Ubuntu and CentOS (both 5 and 7, using Active Directory for user authentication). I most often log on via X Windows / desktop environments and SSH for remote hosts. However, Id like this to be future proof and have the least reliance on system dependencies and other tools as possible.

Ive been using checkbashisms as a simple, automated sanity check for the syntax of my shell-related files. Its not a perfect tool, e.g., Ive already applied a patch to it so that it doesnt complain about the use of command -v in my scripts. While researching, Ive learned that the programs actual purpose is to ensure compliance with Debian policy which, as I understand it, is based on POSIX 2004 rather than 2008 (or its 2013 revision).




Solution

Your

# If the current (login) shell is Bash, then
if [ "${BASH_VERSION:-}" ]; then
  # source ~/.bashrc if it exists.
  if [ -f "$HOME/.bashrc" ]; then
    . "$HOME/.bashrc"
  fi
fi

code is completely POSIX conformant and the best way to check that you're currently running bash. Of course the $BASH_VERSION variable is bash-specific, but that's specifically why you're using it! To check that you're running bash!

Note that $BASH_VERSION will be set whether bash is invoked as bash or sh. Once you've asserted that you're running bash, you can use [ -o posix ] as an indicator that the shell was invoked as sh (though that option is also set when POSIXLY_CORRECT is in the environment or bash is called with -o posix, or with SHELLOPTS=posix in the environment. But in all those cases, bash will behave as if called as sh).


Another variable you could use instead of $BASH_VERSION and that checkbashism doesn't seem to complain about unless passed the -x option is $BASH. That is also specific to bash so one you should also be able to use to determine whether you're running bash or not.


I'd also argue it's not really a proper use of checkbashisms. checkbashisms is a tool to help you write portable sh scripts (as per the sh specification in the Debian policy, a superset of POSIX), it helps identify non-standard syntax introduced by people writing scripts on systems where sh is a symlink to bash.

A .profile is interpreted by different shells, many of which are not POSIX compliant. Generally, you don't use sh as your login shell, but shells like zsh, fish or bash with more advanced interactive features.

bash and zsh, when not called as sh and when their respective profile session file (.bash_profile, .zprofile) are not POSIX conformant (especially zsh) but still read .profile.

So it's not POSIX syntax you want for .profile but a syntax that is compatible with POSIX (for sh), bash and zsh if you're ever to use those shells (possibly even Bourne as the Bourne shell also reads .profile but is not commonly found on Linux-based systems).

checkbashisms would definitely help you find out bashisms but may not point out POSIX syntax that is not compatible with zsh or bash.

Here, if you want to use bash-specific code (like the work around of that bash bug whereby it doesn't read ~/.bashrc in interactive login shells), a better approach would be to have ~/.bash_profile do that (before or after sourcing ~/.profile where you put your common session initialisations).





Comments (5)

  • +0 – That doesn't pass checkbashisms because of the variable used. — Mar 02, 2016 at 22:11  
  • +2 – @ThomasDickey, yes but that's a case where the checkbashisms report should be ignored. All the other solutions given so far are considerably worse. — Mar 02, 2016 at 22:22  
  • +0 – @StéphaneChazelas You say that all the other solutions are worse. What would be wrong with using $0 for this particular case? — Mar 02, 2016 at 23:04  
  • +2 – @AnthonyGeoghegan That doesn't distinguish between bash called as sh and some other shell called as sh. — Mar 02, 2016 at 23:16  
  • +0 – It also gives a false positive if dash or another non-bash shell was incorrectly called with argv[0] == "bash", which is entirely legal, if unlikely. — Mar 03, 2016 at 05:35