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.