Change /bin/sh link temporarily

Solution 1:

If it's a script, just call the script as

bash scriptname.sh

No need to change links at all.

For compiled executable you can go chroot route:

mkdir rootfs
cp -a /usr rootfs/
cp -a /lib rootfs/
cp -a /lib64 rootfs/
cp /bin/bash  rootfs/bin/sh
cp yourprogram  rootfs/
sudo chroot rootfs  sh

And then run your program or sudo chroot rootfs /yourprogram


However, in practice there is no reason why you can't use /bin/bash as a symlink to /bin/sh. In fact, prior to version 6.10 Ubuntu was using /bin/bash as /bin/sh, and then they switched due to /bin/sh being a much faster, leaner implementation of POSIX /bin/sh (that is, it adheres to the POSIX standard for how Unix-like operating system utilities and OS should behave and implement some of their internals), and due to portability reasons. I strongly recommend reading Gilles' answer as well for historical notes on how /bin/dash came about. As for compatibility, scripts written for dash using POSIX features will run with bash being a default shell perfectly fine. Usually, it's the other way around that causes problems - bash has features that aren't required by /bin/sh, like the <<< syntax or arrays.

Additionally, the command in question is probably written with RHEL or CentOS in mind, which does use /bin/bash as a symlink to /bin/sh, suggests two things: they probably targeted specific OS and didn't adhere to POSIX principles. In that case, it would also be a good idea to check what other things the command requires, since if it's really written with another OS in mind, you might run into more problems than just re-linking /bin/sh.

Solution 2:

Two answers already suggest chrooting and bind mounts, and there's a third, closely related option: mount namespaces. Using the unshare program, you can create a new mount namespace, and mounts within this namespace won't affect other namespaces.

For example, in one terminal, I do:

muru|[0] ~ sudo unshare -m /bin/bash
root@muru-1604:~# sudo mount --bind /bin/bash /bin/sh
root@muru-1604:~# /bin/sh --version
GNU bash, version 4.4.18(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later 

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
root@muru-1604:~# sudo -iu muru
muru|[0] ~ /bin/sh --version  # propagates
GNU bash, version 4.4.18(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later 

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

And in another:

$ /bin/sh --version
/bin/sh: 0: Illegal option --

So you could run this inflexible program in its own mount namespace.

Solution 3:

One possibility would be a bind mount of a single file. To do this, you mount the file /bin/bash just over /bin/dash so bash sort of covers or hides dash. Here are the steps (including the reverse):

root@myhost:~# cd /bin

# situation before (bash and dash are different):
root@myhost:/bin# ls -l *sh*
-rwxr-xr-x 1 root root 1113504 Apr  4 20:30 bash
-rwxr-xr-x 1 root root  121432 Jan 25  2018 dash
lrwxrwxrwx 1 root root       4 Jul 13 11:38 sh -> dash
...

# mount /bin/bash over /bin/dash:
root@myhost:/bin# mount --bind /bin/bash /bin/dash

# situation now (bash and dash are the same):
root@myhost:/bin# ls -l *sh*
-rwxr-xr-x 1 root root 1113504 Apr  4 20:30 bash
-rwxr-xr-x 1 root root 1113504 Apr  4 20:30 dash
lrwxrwxrwx 1 root root       4 Jul 13 11:38 sh -> dash
...

# Now everything that runs `/bin/sh` in fact uses `/bin/bash`.

# check what the symlink "sh" says:
root@myhost:/bin# sh --version
GNU bash, version 4.4.19(1)-release (x86_64-pc-linux-gnu)
...

# undo the mount:
root@myhost:/bin# umount /bin/dash 

# situation now (bash and dash are different again):
root@myhost:/bin# ls -l *sh*
-rwxr-xr-x 1 root root 1113504 Apr  4 20:30 bash
-rwxr-xr-x 1 root root  121432 Jan 25  2018 dash
lrwxrwxrwx 1 root root       4 Jul 13 11:38 sh -> dash
...

# check what the symlink "sh" now says:
root@myhost:/bin# sh --version
sh: 0: Illegal option --

I didn't try to mount --bind /bin/bash /bin/sh to directly hide the symlink, though. The above mount trick just makes bash and dash identical so that sh refers to bash although it points to dash. Also, this is a system-wide solution, not only for the current terminal window.


I must confess, this might be overkill and simply changing the symlink temporarily is far easier. I just wanted to show another possible way.