1

I have put together the following to detect if a script is being run by Bash or not:

################################################################################
# Checks whether execution is going through Bash, aborting if it isn't. TinoSino

current_shell="$(
  ps                  `# Report a snapshot of the current processes` \
      -p $$           `# select by PID` \
      -o comm         `# output column: Executable namename` \
  |\
  paste               `# Merge lines of files ` \
      -s              `# paste one file at a time instead of in parallel` \
      -               `# into standard output` \
  |\
  awk                 `# Pick from list of tokens` \
      '{ print $NF }' `# print only last field of the command output`
)"

current_shell="${current_shell#-}" # Remove starting '-' character if present

if [ ! "${current_shell}" = 'bash' ]; then

  echo "This script is meant to be executed by the Bash shell but it isn't."
  echo 'Continuing from another shell may lead to unpredictable results.'
  echo 'Execution will be aborted... now.'

  return 0

fi

unset current_shell
################################################################################

I am not asking you specifically to code review it because you would be sending me to CodeReview; my question is:

  • how would you go about testing whether this "execution guard" put at the top of my script does indeed do its job reliably?

I am thinking about installing Virtual Machines and on each machine to install things like zsh, csh, etc. But it looks way too time-consuming to me. Better ways to do this?

Should you spot an immediate mistake do point it out to me though please. Just glaring bugs waving their legs waiting to be squashed should be squashed, I think.

Robottinosino
  • 10,384
  • 17
  • 59
  • 97
  • how did you start your script? `./foo.sh` or `bash foo.sh` or `sh foo.sh`? (assume under same dir) – Kent Mar 15 '13 at 23:24

2 Answers2

7

This is better written as

if [ -z "$BASH_VERSION" ]
then
   echo "Please run me in bash"
   exit 1
fi

As for testing, get a list of non-bash shells from /etc/shells, and just run the script with each of them verifying that you get your error message.

that other guy
  • 116,971
  • 11
  • 170
  • 194
  • And this is guaranteed not to be exported to subshells invoked by Bash? – Robottinosino Mar 15 '13 at 23:44
  • Part of the question is answered: read `/etc/shells`, whose existence I did not know about. Thanks. I am not sure about your `-z "$BASH_VERSION"` though, I may be wrong. Ah, and exit is too tough, I think it's better to return. – Robottinosino Mar 15 '13 at 23:45
  • It doesn't happen by default. Nothing theoretically stops you from exporting a variable called BASH_VERSION in another shell of course, just like nothing stops you from symlinking dash to bash to defeat your original script. – that other guy Mar 15 '13 at 23:50
  • I grew skeptical about this system reading this: http://stackoverflow.com/questions/3199893/howto-detect-bash-from-shell-script – Robottinosino Mar 15 '13 at 23:53
  • The system of relying on $SHELL or $0, variables set by the caller? Yes, I agree. You should be using a variable set by the shell itself, like $BASH_VERSION. – that other guy Mar 15 '13 at 23:56
  • You convinced me. :) I would use `[[` rather than `[` not to have to double-quote the variable being tested.. and `return` rather than `exit` (`exits` bombs on GNOME 2 login which triggers something that sources the `.profile`...) but I am now convinced as I had asked something very similar before too. – Robottinosino Mar 16 '13 at 00:08
  • I set up the testing from `/etc/shells` too. Last comment: why do you use `if ... do ... done` rather than `if ... then ... fi`? – Robottinosino Mar 16 '13 at 00:13
  • 1
    `[[` is not recognized in all shells, and when it isn't, it'll return failure and keep running the rest of your script. `return` is appropriate if this is sourced or a function, but you didn't mention anything about that so I treated it as a standalone script. As for do/done, that was a typo :P – that other guy Mar 16 '13 at 00:14
  • I am sold on `[` too then. Thanks a lot! – Robottinosino Mar 16 '13 at 00:16
2

I would only recommend rolling your own if it isn't critical to "guarantee" correct results. I don't think such a guarantee is even possible, but most of the time you're at most targeting a few shells and only care about modern versions. Very few people should even care about version detection. Writing portable code while going outside of POSIX requires knowing what you're doing.

Don't bother detecting the shell just to abort. If people want to shoot themselves in the foot by ignoring the shebang that's their problem.

ormaaj
  • 6,201
  • 29
  • 34
  • Re: it's stupid to roll your own -> you are absolutely right. Do any of those scripts come in APT packages for Ubuntu that you know of? (I checked `dpkg-query -S`). I should just use tried and tested scripts. Disagree with "letting them shoot themselves in the foot". Upvoting to reward the idea: use something that's already out there. Just need to find out how to deploy it with consistency.. (e.g. package distrib) – Robottinosino Mar 16 '13 at 19:13
  • which_interpreter makes my eyes hurt. – jordanm Mar 16 '13 at 20:06