ChatGPT解决这个技术问题 Extra ChatGPT

What is the preferred Bash shebang?

Is there any Bash shebang objectively better than the others for most uses?

#!/usr/bin/env bash

#!/bin/bash

#!/bin/sh

#!/bin/sh -

etc

I vaguely recall a long time ago hearing that adding a dash to the end prevents someone passing a command to your script, but can’t find any details on that.

And its /usr/local/bin/bash on OpenBSD.
Adding the dash is meant to prevent a certain kind of setuid root spoofing attacks, see security.stackexchange.com/questions/45490/…
I would upvote this, but it has a score of 1337 and I don't want to disturb it!
#!/usr/bin/env bash poses a privilege escalation security threat when a suid program executes a bash script that has such a shebang. The user can simply manipulate his PATH and get an arbitrary bash executable to be run instead, with elevated privileges.

l
l0b0

You should use #!/usr/bin/env bash for portability: different *nixes put bash in different places, and using /usr/bin/env is a workaround to run the first bash found on the PATH. And sh is not bash.


Thanks. Also looks like adding - to the end of $!/usr/bin/env bash - won't do anything since only one argument is allowed by *nix in the shebang, and that is used by 'bash'. That's apparently only useful for preventing malicious arguments being passed to the script on the commandline if the script's shebang is one of the others with no arguments (/bin/sh, etc).
@Ray bash doesn't live in /bin on all systems.
Same for me, I just added it to an alias: alias shebang='echo "#!/usr/bin/env bash"', now I just have to open the terminal and type shebang instead of going here.
This answer is deceptive. POSIX does not say that env is at /usr/bin/env. It could be at /bin/env or anywhere in fact, as long as it is in the path. It could be at /dummy/env if /dummy is in PATH. Shebang itself is undefined under POSIX, so I could make #!stop toaster start the USB coffee machine and be POSIX compliant. So #!/usr/bin/env bash isn't particularly better than #!/bin/bash, it could be less portable depending.
@darkfeline Portability isn't absolute - it is mathematically impossible to make any script that will do the same thing on every platform. As of 2012 through 2018 /usr/bin/env exists on more machines than either of /bin/bash xor /usr/bin/bash, so a script that starts with this line will do the expected thing on as many machines as possible.
K
Keith Thompson

I recommend using:

#!/bin/bash

It's not 100% portable (some systems place bash in a location other than /bin), but the fact that a lot of existing scripts use #!/bin/bash pressures various operating systems to make /bin/bash at least a symlink to the main location.

The alternative of:

#!/usr/bin/env bash

has been suggested -- but there's no guarantee that the env command is in /usr/bin (and I've used systems where it isn't). Furthermore, this form will use the first instance of bash in the current users $PATH, which might not be a suitable version of the bash shell.

(But /usr/bin/env should work on any reasonably modern system, either because env is in /usr/bin or because the system does something to make it work. The system I referred to above was SunOS 4, which I probably haven't used in about 25 years.)

If you need a script to run on a system that doesn't have /bin/bash, you can modify the script to point to the correct location (that's admittedly inconvenient).

I've discussed the tradeoffs in greater depth in my answer to this question.

A somewhat obscure update: One system I use, Termux, a desktop-Linux-like layer that runs under Android, doesn't have /bin/bash (bash is /data/data/com.termux/files/usr/bin/bash) -- but it has special handling to support #!/bin/bash.


2-years later and this is still the best advice here. If the simple solution doesn't work then you've got to question your earlier decisions. The accepted and most upvoted answer isn't wrong, it's just not right :)
C
CodeClown42

/bin/sh is usually a link to the system's default shell, which is often bash but on, e.g., Debian systems is the lighter weight dash. Either way, the original Bourne shell is sh, so if your script uses some bash (2nd generation, "Bourne Again sh") specific features ([[ ]] tests, arrays, various sugary things, etc.), then you should be more specific and use the later. This way, on systems where bash is not installed, your script won't run. I understand there may be an exciting trilogy of films about this evolution...but that could be hearsay.

Also note that when evoked as sh, bash to some extent behaves as POSIX standard sh (see also the GNU docs about this).


The Public Domain Korn Shell (pdksh) is default on OpenBSD.
Most systems will not link /bin/sh to anywhere in /usr as that would make it rather hard for the init scripts to run before /usr is mounted.
@aij I don't know why I put "many or most" there -- I'm a fedora user, where /bin and /sbin for years have just been symlinks by default, to /usr/bin and /usr/sbin, so in that context /bin/sh is a link to bash and the actual directory is /usr/bin. But I'll correct the above.
n
nbro

Using a shebang line to invoke the appropriate interpreter is not just for BASH. You can use the shebang for any interpreted language on your system such as Perl, Python, PHP (CLI) and many others. By the way, the shebang

#!/bin/sh -

(it can also be two dashes, i.e. --) ends bash options everything after will be treated as filenames and arguments.

Using the env command makes your script portable and allows you to setup custom environments for your script hence portable scripts should use

#!/usr/bin/env bash

Or for whatever the language such as for Perl

#!/usr/bin/env perl

Be sure to look at the man pages for bash:

man bash

and env:

man env

Note: On Debian and Debian-based systems, like Ubuntu, sh is linked to dash not bash. As all system scripts use sh. This allows bash to grow and the system to stay stable, according to Debian.

Also, to keep invocation *nix like I never use file extensions on shebang invoked scripts, as you cannot omit the extension on invocation on executables as you can on Windows. The file command can identify it as a script.


N
Nathan Smith

It really depends on how you write your bash scripts. If your /bin/sh is symlinked to bash, when bash is invoked as sh, some features are unavailable.

If you want bash-specific, non-POSIX features, use #!/bin/bash


Bash is not installed on OpenBSD. If you install it via pkg_add, then its located in /usr/local/bin, which may not be on-path.
how about a POSIX feature?
T
Tom Ekberg

Add one more vote to the #!/usr/bin/env approach. I use virtual environments a lot, in my case I use the python installed in the virtualenv. Using #!/usr/bin/python may not be the python I want. I get the right python using #!/usr/bin/env python.


Please answer to the question: this is about the best way to invoke a bash script, not a pythong script. Both have drastically different requirements as bash location is always under /bin (contraru to python in a virtualenv) and python versions are incompatible whereas a bash script will generally run with any recent bash version. Not the same problem space. This is about bash after all, not python.
w
weberjn

#!/bin/sh

as most scripts do not need specific bash feature and should be written for sh.

Also, this makes scripts work on the BSDs, which do not have bash per default.


But the question is what to use for Bash scripts specifically. This has the distinct and potentially serious drawback that it will not work for Bash scripts (i.e. anything which uses Bash-only features). This is a common pitfall for newbies. See also Difference between sh and bash
The person asking the question specifically asks whether /bin/sh is a good shebang for bash scripts. So I think that weberjn's answer is not out of scope.