9

I have a piece of software that requires /bin/sh to be Bash, but for Ubuntu the default is Dash and I want to keep it the default; I don't want to change it to Bash permanently.

Is there a way to change it only for a running terminal session? So a program running in this terminal will see /bin/sh linked to bash but the rest of the system will still see Dash? Or can I trick the software to see /bin/sh as Bash even if its not?

I didn't write this software and hacking it to use /bin/bash instead of /bin/sh is not really an option.

David Foerster
  • 36,264
  • 56
  • 94
  • 147
corwin
  • 103
  • 2
    You can change it temporarily - but not (AFAIK) limit the scope to a single terminal session. See for example /bin/sh is a symbolic link that doesn't point to /bin/bash – steeldriver Sep 11 '18 at 14:45
  • could you make an alias... alias sh=bash ? and then just delete the alias from .bashrc when you are done (it will be at the end of the file) this should work and not affect teh entire system and be very easy to undo... – Joshua Besneatte Sep 11 '18 at 15:38
  • 2
    Possibly of interest: https://unix.stackexchange.com/questions/468289/temporarily-replace-bin-sh-for-script-execution – ejjl Sep 11 '18 at 17:21
  • 7
    Whatever you do, please also report this as a bug for the software in question. Because assuming /bin/sh is bash is a bug, and it causes actual problems (as you're finding out). If no one complains, it may never get changed. – marcelm Sep 11 '18 at 22:38
  • @marcelm It may not be a bug, since software author may target RHEL and CentOS. On those OS /bin/sh is actually symlink to bash. In fact, without naming names, I do know quite a large engineering company that does it this way. Not POSIX compliant, but then again they explicitly state they only support RHEL. – Sergiy Kolodyazhnyy Sep 12 '18 at 00:40
  • 1
    @SergiyKolodyazhnyy If the bug doesn't cause problems on the only platform(s) they support, then they can probably get away with it. It's still a bug though. – marcelm Sep 12 '18 at 10:30
  • @SergiyKolodyazhnyy Yeah I'm honestly on the fence as to whether I'd still call it a bug. I get that the program will function as intended on the target platforms, but still, the shebang is improperly formed given the known constraints. Certainly, if it were my project, I'd change it just to be more precise if nothing else. – Lightness Races in Orbit Sep 12 '18 at 13:46
  • 1
    The software is Petalinux released by a "small" company called Xilinx, and according to the documentation Ubuntu 16.04 is supported (along with CentOS and RHEL), so I would say its a bug. – corwin Sep 13 '18 at 07:43

4 Answers4

14

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.

Melebius
  • 11,431
  • 9
  • 52
  • 78
Sergiy Kolodyazhnyy
  • 105,154
  • 20
  • 279
  • 497
10

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.

Sergiy Kolodyazhnyy
  • 105,154
  • 20
  • 279
  • 497
muru
  • 197,895
  • 55
  • 485
  • 740
5

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.

PerlDuck
  • 13,335
1

You should be able to change it for just the current session by using an alias. Before running your command in the terminal:

alias sh=bash

This will be temporary and only active in the terminal it was executed from.

HOWEVER: This will NOT WORK if your script uses absolute paths.

Good idea as such, but if the software directly calls /bin/sh with an explicit pathname, it will not work. Anyway, that software does not seem to be very properly designed making such assumptions. I would probably run it from a script that prepares and resets the proper environment if I had to use it at all. – vanadium

Unfortunately, "hacking" the script might be your only option. Per convo with @vanadium, you could create a wrapper script like this:

#!/bin/bash
sudo ln -sf /bin/bash /bin/sh
/run/my/script
sudo ln -sf /bin/dash /bin/sh

However, during the duration of your script, you better hope nothing on your system explicitly requires dash.

Joshua Besneatte
  • 4,773
  • 5
  • 23
  • 42
  • 3
    Good idea as such, but if the software directly calls /bin/sh with an explicit pathname, it will not work. Anyway, that software does not seem to be very properly designed making such assumptions. I would probably run it from a script that prepares and resets the proper environment if I had to use it at all. – vanadium Sep 11 '18 at 16:24
  • I would be interested to see how you would go about preparing the environment. would you use chroot? – Joshua Besneatte Sep 11 '18 at 16:34
  • I did not have such ambitious ideas. I was just thinking of a script that would temporarily have sh link to bash and reset when done. The main problem in this question is with the "piece of software" concerned, I think. – vanadium Sep 11 '18 at 17:17
  • what would happen if something else needed dash whilst the symbolic link was moved.... something like ln -sf /bin/bash /bin/sh at the begginning and ln -sf /bin/dash /bin/sh when done? – Joshua Besneatte Sep 11 '18 at 17:23
  • Most other processes probably will happily use bash instead of dash if the link is changed. Yes, in that vain, but to mimic the current situation, I would make relative links, i.e. "cd /bin ; ln -sf bash sh", but that is probably a purist detail that won't matter in practice. – vanadium Sep 11 '18 at 17:27