
No, it's not a Ricky Martin song.
Wikpedia says the shebang also known as a sharp-exclamation, sha-bang, hashbang, pound-bang, or hash-pling. No matter what you call it, it has been around since 80's.
Simply put, a shebang lets a file tell your Unix-like operating system what executable should interpret your file (an "interpreter directive"), and it's used whenever your file is invoked like an executable.
Shebangs are always the first line of a file, and they look like this:
#!/usr/bin/env sh
echo "I should be executed by a POSIX-compliant shell!"#!/usr/bin/env bash
echo "I should be executed by Bash!"#!/usr/bin/env python3
print("I should be executed by Python 3!")#!/usr/bin/env node
console.log("I should be executed by Node.js!")and then if that file is named my_executable (with no extension, to prove that the OS won't know the right interpreter without reading the file), it can be executed like this:
$ # (the file has to be made executable first)
$ chmod +x my_executable
$ # It can be invoked with a relative path
$ ./my_executable
$ # It can be invoked with an absolute path
$ "$(pwd)/my_executable"If a file does not include a shebang, it will be interpreted by current shell, which means different environments can behave differently:
# We don't know what this will be executed by
echo "I was executed by ${SHELL}!"Syntax
Shebangs look like this, and they must be the first line in a file:
#! <executable> [optional-single-arg](Though the space(s)/tab(s) after #! are optional, and many people choose to omit them.)
Putting this in your source file is safe because # is a single-line comment marker in most scripting languages, so the interpreter will ignore it during execution.
The <executable> should be an absolute (non-relative) path to either an interpreter (/bin/sh, /bin/bash, /usr/bin/pwsh, /usr/bin/python3, /usr/bin/ruby, etc.), or an executable that can find an interpreter (/usr/bin/env). Some OSes allow the executable to be a script and not a binary, but macOS notably does not.
Shebangs let files assert what interpreter should run them (and IDEs frequently pick up on them for syntax highlighting), but they are just shortcuts to more verbose commands. The executable specified will be invoked with the optional argument, and then the name of the script, and then any CLI arguments after.
Here are some examples that execute the same way:
my_script.sh:bash#!/usr/bin/env bash echo "I should be executed by Bash!"● ● ●shell$ # Use the shebang $ chmod +x my_script.sh $ ./my_script.sh I should be executed by Bash! $ # Don't use the shebang $ /usr/bin/env bash ./my_script.sh I should be executed by Bash! $ "$(which bash)" ./my_script.sh I should be executed by Bash! $ bash ./my_script.sh I should be executed by Bash!my_script.py:python#!/usr/bin/env python3 import sys print("I should be executed by Python 3, with the args:", sys.argv[1:])● ● ●shell$ # Use the shebang $ chmod +x my_script.py $ ./my_script.py --arg-one --arg-two I should be executed by Python 3, with the args: ['--arg-one', '--arg-two'] $ # Don't use the shebang $ /usr/bin/env python3 ./my_script.py --arg-one --arg-two I should be executed by Python 3, with the args: ['--arg-one', '--arg-two'] $ "$(which python3)" ./my_script.py --arg-one --arg-two I should be executed by Python 3, with the args: ['--arg-one', '--arg-two'] $ python3 ./my_script.py --arg-one --arg-two I should be executed by Python 3, with the args: ['--arg-one', '--arg-two']
Portability
Using the #! /usr/bin/env <interpreter> style for shebangs is typically more "portable," meaning that it works more reliably across a wide variety of OSes environments.
env <command> is similar to which <programname> in that it will search your $PATH and return the first executable found matching the given name. But while which prints the path of the executable, env will invoke the executable and pass all remaining arguments to it. Example:
$ which python3
/usr/bin/python3
$ /usr/bin/env python3 -c 'print("hello world")'
hello worldYou can't use #! python3 for your shebang, the OS will treat that as path relative to your current working directory, which would be the same as:
$ ./python3 -c 'print("hello world")'
bash: ./python3: No such file or directory
$ "$(pwd)/python3" -c 'print("hello world")'
bash: /home/ubuntu/python3: No such file or directoryUsing #! /usr/bin/env <interpreter> is particularly important if your interpreter is frequently in different locations in different OSes, such as python3, ruby, node, and perl.
For example, on macOS, Python v3.9.6 could be in any one of these locations:
/usr/bin/python3is provided by the OS (and is typically quite old)/Library/Frameworks/Python.framework/Versions/3.9/bin/python3is where the official installer puts it/opt/homebrew/Cellar/python@3.9/3.9.6/bin/python3is where Homebrew puts it on an Apple Silicon Mac
So it is more reliable to use /usr/bin/env to find where python3 is, plus it respects your $PATH ordering:
#!/usr/bin/env python3
import sys
print("I was executed by '" + sys.executable + "'!")(This is less important for shell executables such as /bin/bash that should always exist in the same location, but it also isn't dangerous to default to using /usr/bin/env.)
Windows
Both Command Prompt (cmd.exe) and PowerShell do not natively interpret shebangs. Further, shebangs will cause problems for Command Prompt, as comments are started with REM or :: and not #.
Instead, Windows will use file extensions and associations to determine which executable to use.
(Unix-like shells such as Windows Subsystem for Linux (WSL) , Cygwin , and MSYS2 all handle shebangs correctly.)





