How to use shebang #! in Bash

Aug 09, 2023#bash

Shebang is a special line that tells the operating system which interpreter to use to execute the rest of the script. It is useful for making your files executable without specifying the interpreter from the command line like this ./my_script.sh instead of bash my_script.sh.

The shebang line must be the first line in the script, and it must start with #! without any spaces or other characters before them, followed by the path to the Bash binary, such as #!/bin/bash or #!/usr/bin/env bash.

#!/bin/bash

# Print only the even numbers from 1 to 10
for i in {1..10}; do
  if [[ $((i % 2)) -ne 0 ]]; then
    continue
  fi
  echo $i
done

If you omit the shebang line, the system will try to guess the interpreter based on the file extension, the file content, or the default command line interpreter. However, this may not always work as expected, and it may cause errors or unexpected behavior.

Basic syntax

The shebang syntax is not a Bash-specific feature, but a convention that is recognized by most operating systems. It’s also used in other scripting languages, such as Python, Perl, and Ruby.

#!/path/to/interpreter [optional arguments]

Here’s a breakdown of each part:

  • #!: The shebang indicator. These characters must appear at the very beginning of the file.
  • /path/to/interpreter: The absolute path to the interpreter executable that should be used to run the script. This path specifies which program will interpret and execute the script’s commands.
  • [optional arguments]: You can optionally provide arguments that will be passed to the interpreter when the script is executed. This is particularly useful if the interpreter supports command-line options that modify its behavior.

Here are a few specific shebang lines:

  • #!/bin/sh
  • #!/bin/bash
  • #!/usr/bin/python3
  • #!/usr/bin/perl
  • #!/bin/bash -x: Bash shell with the -x option, which enables debugging mode

Remember that the shebang line is used to execute the script directly from the command line. It’s important to use the correct interpreter’s path in the shebang line to ensure that the script is executed by the intended interpreter.

Using env utility

Another option for specifying the interpreter path is to use the env utility, which can find the interpreter from the user’s PATH environmental variable.

#!/usr/bin/env interpreter [optional arguments]

This can make the file more portable and flexible, as it does not depend on a fixed location of the interpreter. However, this may also introduce some security risks, as it allows anyone to modify the user’s PATH and run a malicious program instead of the intended interpreter.

  • #!/usr/bin/env bash
  • #!/usr/bin/env python3
  • #!/usr/bin/env perl
  • #!/usr/bin/env -S bash -euo pipefail

The order of directories in the PATH is significant because it determines the precedence of executables with the same name in different directories. If you have multiple versions of an interpreter installed in different directories, the one that appears earlier in the PATH will be used.

You can view your current PATH by running the echo $PATH command in a terminal. To modify the PATH, you can use the export command, but be cautious when making changes to avoid unintentional consequences.

Using #!/bin/false

The /bin/false is a command that does nothing and always returns a non-zero exit code, which means failure. Therefore, when a script has #!/bin/false as its shebang, it means that the script will not be executed and will always fail.

One possible reason to use is to prevent a script from being run accidentally or maliciously. For example, if a script contains some sensitive information or commands that are not meant to be executed, using #!/bin/false can prevent someone from running the script by mistake or on purpose.

Another possible reason is to create a dummy script that can be used as a placeholder or a stub for testing purposes. For example, if a script is not yet implemented or completed, using #!/bin/false can indicate that the script is not ready and will always fail.

However, using #!/bin/false as a shebang may not be very user-friendly or informative, as it does not provide any feedback or explanation to the user who tries to run the script.

Using #!/bin/sh

You should use #!/bin/sh when you want to write a portable shell script that can run on any system that has a POSIX-compliant shell. The #!/bin/sh line tells the operating system to use the default system shell, which is usually a link to a POSIX-compatible shell such as bash, dash, ksh, or zsh.

By using #!/bin/sh, you can ensure that your script will work on any system that follows the POSIX standard, regardless of the actual location or name of the shell executable.

However, using #!/bin/sh also means that you have to stick to the features and syntax that are defined by the POSIX specification, and avoid using any extensions or enhancements that are specific to a certain shell.

For example, you cannot use arrays, associative arrays, brace expansion, or process substitution in a #!/bin/sh script, as they are not part of the POSIX standard.

If you want to use these features, you have to use a specific shell indicate it in the shebang line.

Overriding shebang when executing a script

To override the shebang line of a script, you can execute the script by explicitly specifying the interpreter you want to use on the command line. This can be useful in situations where you want to use a different interpreter than the one specified in the shebang line, or if the shebang line is incorrect or not compatible with your environment.

/path/to/interpreter script_file.sh

Replace /path/to/interpreter with the absolute path to the interpreter you want to use or name of interpreter already available in PATH, and script_file.sh with the name of the script file you want to execute.

For example, if you have a script named myscript.sh with the following shebang line:

#!/bin/bash

And you want to run it using the zsh interpreter instead of bash, you can do:

/usr/bin/zsh myscript.sh

This will execute the script myscript.sh using the zsh interpreter, regardless of the shebang line in the script.

Keep in mind that when you override the shebang line in this way, you’re explicitly specifying the interpreter for that particular execution only. The shebang line in the script itself remains unchanged, and future executions without specifying an interpreter will still use the interpreter specified in the shebang line.

Overriding the shebang line to run a script with a different interpreter than what’s specified in the script’s shebang line can carry certain risks and considerations. The script may have been written with assumptions about the behavior of a specific interpreter. Using a different interpreter might lead to unexpected behavior, errors, or incorrect results.

In general, it’s safer and more reliable to modify the shebang line in the script itself if you want to change the interpreter permanently.

Overriding the shebang line for a one-time use should be done cautiously and with an understanding of the potential risks. If you find the need to regularly run the script with a different interpreter, consider adapting the script to be more flexible and compatible across multiple interpreters.

Common shell interpreters

Each interpreter has its strengths and purposes. Choose the one that matches your needs, from compatibility and simplicity to advanced features and interactivity.

  • Bash (GNU Bourne Again SHell): Feature-rich, powerful scripting capabilities, widespread, suitable for complex automation tasks.
  • Sh (Bourne Shell): Basic scripting features, good for simple scripts aiming at wide compatibility. Often used for scripts that need to run on a wide range of systems due to its widespread availability, but it lacks many advanced features of newer shells.
  • Zsh (Z Shell): Interactive features, advanced customization, suitable for power users and scripting. Starting with macOS Catalina (10.15), released in October 2019, Apple switched the default shell from Bash to Zsh.
  • Dash: Minimal, optimized for speed, often used for system startup scripts.
  • Ksh (KornShell): Advanced scripting, arrays, suited for complex tasks.
  • Fish (Friendly Interactive Shell): User-friendly, syntax highlighting, well-suited for interactive use.
  • Csh (C Shell): C-like syntax, interactive features, not recommended for scripting due to limitations.