I have installed bash 4 with Homebrew and bash --version shows me the version 4.

If I have following test script:

# test-version.sh

And I make it executable chmod +x configurer.sh and run it ./test-version.sh I also get the version 4.

But if I run it with the sh command sh test-version.sh I get the version 3.

I have put the new shell into /etc/shells:

sudo bash -c 'echo /usr/local/bin/bash >> /etc/shells'

And changed to the new shell:

 chsh -s /usr/local/bin/bash

I also changed the path in iTerm Settings > Profiles > Command to /usr/local/bin/bash.


EDIT: I've come to realize that it's good to leave sh alone. When wanting to run scripts with Bash 4 just don't use sh.

  • Can you please tell us the out put of echo $PATH? – airsquared Oct 25 '18 at 16:58
  • When you run ‘sh command’ you are starting a new shell with its own environment and path. Is there a reason you want to do this? Why not start your script with the shevang and /usr/env bash line so that it picks up the gash shell as you expect? – Allan Oct 25 '18 at 18:48
  • As sh runs the base POSIX shell ie no bash extentions How would a sh script have different behaviour in bash 3 or 4 or zsh - or are there particular bugs – mmmmmm Jun 1 at 13:58

I used homebrew to install BASH4 and I use the shebang #!/bin/bash every time. This works for me with both sh and ./ styles of running.

| improve this answer | |
  • Have you linked that to /usr/local/bin/bash? For me that shebang gives me Bash 3 always. – any_h Oct 26 '18 at 4:54

A simple fix if you just want to be able to write "sh" and have it run the new bash is to create a link like this:

ln -s /usr/local/bin/bash /usr/local/bin/sh

This won't help you if you have for example scripts that start with #!/bin/sh or similar.

In order to change that sh, you'll need to either copy over the /usr/local/bin/bash file to overwrite /bin/sh, like this:

  cp /usr/local/bin/bash /bin/sh

or create a link between the two:

  ln -sf /usr/local/bin/Bash /bin/sh

Please take a backup copy of the sh binary before doing so.

However, I would advice to leave "sh" alone as it is the system shell used during bootup, shutdown, and by the system in general. Even though the newer bash version is largely compatible, it would be tiresome if booting fails now or after an OS upgrade because you have substituted the shell.

| improve this answer | |
  • @abc There's no point in changing the PATH variable. /usr/local/bin and /usr/bin already has higher preference than /bin. I already wrote in the answer, that it is not advisable to replace the sh file in general. – jksoegaard Oct 25 '18 at 17:08
  • Oh, I didn't see that. You should use links instead of copying the file over, and rename the old sh to something else so you can always recover it if needed. – airsquared Oct 25 '18 at 17:12
  • For making links, I think it's usually better to use symlinks than hard links. – airsquared Oct 25 '18 at 17:13
  • @abc The answer is already with symlinks - there’s no hard links at all.... – jksoegaard Oct 25 '18 at 17:21
  • Symlinks are created with ln -s. Hard links are created with plain ln. See here.(I've edited the answer to use symlinks) – airsquared Oct 25 '18 at 17:47

By running man sh in a terminal on macOS, we can learn the sh command determines the shell first by evaluating a symbolic link:

     sh is a POSIX-compliant command interpreter (shell).  It is implemented by re-execing as either bash(1), dash(1), or zsh(1) as determined by the sym-
     bolic link located at /private/var/select/sh.  If /private/var/select/sh does not exist or does not point to a valid shell, sh will use one of the
     supported shells.

Verifying this as follows:

$ l /private/var/select
drwxr-xr-x - root 13 Oct  2019  .
drwxr-xr-x - root 26 May 21:25  ..
lrwxr-xr-x 9 root 13 Oct  2019  sh -> /bin/bash

If you wish to alter the default shell, you can update this symbolic link accordingly.

In addition, I would verify that whichever shell you use is sanctioned in your /etc/shells file:

$ cat /etc/shells
# List of acceptable shells for chpass(1).
# Ftpd will not allow users to connect who are not using
# one of these shells.


Verifying man page

To verify what the man page indicates is true, we can do a simple test.

In one session start watching file system activity for any access to the /private/var/select/sh link:

$ sudo fs_usage sh | grep -E '/private/var/select/sh'

In a second terminal run the following:

$ /bin/sh -c ls

And note the output similar to the following in the fs_usage session:

10:55:26  readlink          /private/var/select/sh                                                           0.000030   sh
| improve this answer | |
  • @nohillside evidently you didn't run man sh on macOS before responding to my answer, which I now suggest you try. I provided output from the man page of macOS 10.15.5. Furthermore, running a command like /bin/sh -c ls and monitoring file system usage using sudo fs_usage "sh" proves what the man page states. I submit the following output from fs_usage, which demonstrates sh accessing the link 10:47:14.973347 readlink /private/var/select/sh 0.000018 sh.3164073 – Stuart Carnie May 31 at 17:52
  • @nohillside I've further updated my answer to clarify this was done on macOS, POSIX certified since 10.5 en.wikipedia.org/wiki/POSIX#POSIX-certified – Stuart Carnie May 31 at 17:58
  • The debate of macOS/Linux and POSIX aside...how exactly does this answer address the OP's actual question? What in here can I (as a new user) utilize to ensure that my script runs with Bash version 4? – Allan May 31 at 18:08
  • Oh, so Catalina changed this significantly. Thanks for coming back, I‘ve learned something here. – nohillside May 31 at 18:42
  • The question by the OP is “How to change the sh command to run scripts in bash 4”. My post shares and specifies from the official man page that you can update the symbolic link in /private/var/select/sh to refer to bash 4 – Stuart Carnie Jun 1 at 6:21

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .