# The Secret Behind the First Line of Linux Scripts: What Exactly Are `#!/usr/bin/env bash` and `#!/bin/bash`? When writing a script in [[Linux]], it's common practice to start with one of these lines: ```bash #!/usr/bin/env bash ``` or ```bash #!/bin/bash ``` They might look like mere comments at first glance, but what is the true **identity** of this single line? And what exactly are the differences between the two? In this post, we'll thoroughly understand this crucial line, clarify its purpose, and discuss when to use each method. --- ## 1. Not a Comment: What is a shebang? {#sec-9f8041c620ba} This line, starting with `#!`, is called a **shebang**. ```bash #!/bin/bash ``` From a shell's perspective, starting with `#` certainly makes it look like a "comment". However, from the **operating system's (kernel's)** perspective, it's not a comment but rather: > "An instruction that tells where the **interpreter program** to execute this script is located." This means: * `#!/bin/bash` → "Execute this file with `/bin/bash`" * `#!/usr/bin/env bash` → "Find the `bash` interpreter via `env` and execute this file with it" --- ## 2. How Does the Kernel Execute Scripts? {#sec-33d96b8d8f01} Simplifying the execution process, it works like this: 1. The user executes a script with execute permissions ```bash chmod +x script.sh ./script.sh ``` 2. The kernel reads `script.sh` 3. It checks if the **first two characters** of the file are `#!` 4. If they are, it interprets the rest of the line as: * "the interpreter's path + arguments" and * executes that program, **passing the script file path as an argument**. For example, if `script.sh`'s first line is: ```bash #!/bin/bash ``` The kernel's actual action can be roughly thought of as: ```bash /bin/bash script.sh ``` In essence, the kernel performs a similar action to what we would do by directly running `bash script.sh`. > Note: > There **must not be any spaces** before `#!/`. > The **first character** of the file must be `#`, and the second must be `!`. --- ## 3. Meaning and Characteristics of `#!/bin/bash` {#sec-52f9e12dce0d} This is the most frequently seen form. ```bash #!/bin/bash ``` ### Meaning {#sec-a97a945792d4} * "This is a **bash script**, and `bash` is located at `/bin/bash`." * The kernel always executes `/bin/bash` when running this script. ### Advantages {#sec-a01bf708579d} * **Clarity**: Since `/bin/bash` is always used, it's easy to predict which bash will be executed. * **Performance/Simplicity**: It executes directly without going through `env`, so there's no path lookup process. * In many [[Linux]] distributions, `/bin/bash` is virtually considered a "standard location". ### Disadvantages {#sec-89064c01f1ea} * **May not be portable** * On some systems, bash might be located at a different path, such as `/usr/bin/bash` or `/usr/local/bin/bash`. * Some systems might not have bash installed at all, only `/bin/sh`. * Paths can differ, especially on **macOS, BSD-based systems, NixOS, and certain container environments**. --- ## 4. Meaning and Characteristics of `#!/usr/bin/env bash` {#sec-97cd6f02458d} This is a form commonly seen in modern scripts. ```bash #!/usr/bin/env bash ``` The key here is `/usr/bin/env`. * `env` is a utility that helps with "setting/checking environment variables + searching for programs in PATH". * You can think of the kernel actually executing it like this: ```bash /usr/bin/env bash script.sh ``` * `env` looks at the system's `PATH` environment variable and finds the `bash` executable within it to run. ### Advantages {#sec-9bc2075d78b3} 1. **Portability (Works well in various environments)** * Whether bash is in `/bin/bash`, `/usr/bin/bash`, or `/usr/local/bin/bash`, * `env` will find it as long as it's properly registered in `PATH`. 2. **Uses bash appropriate for the user's environment** * If a user has customized their `PATH` to prioritize a specific bash version, that bash will be used. 3. **Same pattern used in Python and other languages** ```sh #!/usr/bin/env python3 ``` ### Disadvantages {#sec-0ba7b1b3de08} 1. **Prerequisite: `/usr/bin/env` must exist** * While present on almost all modern Unix/[[Linux]] systems, it might not be in very specialized environments. 2. **Different interpreters might be picked up depending on PATH** * If the PATH configuration is misconfigured or an unexpected bash is found first, an unintended version might be executed. 3. **Requires caution from a security perspective** * In highly security-sensitive environments, **absolute paths** are sometimes preferred over PATH-based interpreter lookup. --- ## 5. Comparison Summary of Both Methods {#sec-f327651f1197} Let's summarize with a simple comparison table. | Category | #!/bin/bash | #!/usr/bin/env bash | | :------------------------------ | :--------------------- | :---------------------------------- | | Interpreter Location Method | Absolute path fixed | Searched via `PATH` | | Portability (Multi-system compatibility) | Low (breaks if path differs) | High (OK if bash is in PATH) | | Which bash is used | Always `/bin/bash` | First `bash` found in PATH | | Guaranteed intended version | Relatively easy | Can vary depending on PATH status | | Security/Control | Stronger (fixed path) | Slightly looser (PATH dependent) | | General modern trend | Relatively older style | More often recommended nowadays | --- ## 6. When to Use Which Method? {#sec-a9bac1ab9ba4} To answer the question, "So, what should I use?", let's break it down by situation. ### 1) Personal / Team Development Scripts (General Development Environment) {#sec-fc5216000f29} * Generally, the following is recommended: ```bash #!/usr/bin/env bash ``` * Reason: * The bash location might differ across developer-managed servers, local environments, CI environments, etc. * PATH-based lookup and execution is more flexible, and modern tools/scripts prefer this approach. ### 2) Operational Scripts Tailored for Specific Server Environments {#sec-204ac6ba64d3} * For instance, if all servers within a company commonly have bash installed at `/bin/bash`, and * the server environment is quite stable: ```bash #!/bin/bash ``` * Reason: * Ensures the use of the same interpreter every time. * Reduces unexpected behavior caused by PATH modifications. ### 3) If You Want Maximum Portability? {#sec-6ef1b12d728e} * If you're in an environment where you think "bash might not even be present?", then you should reconsider if a bash-dependent script is appropriate in the first place. * If possible, write it in `sh`: ```bash #!/bin/sh ``` * This will run in a much wider range of environments. However, you must avoid bash-specific syntax (`[[ ]]`, arrays, extended string processing, etc.). --- ## 7. Practical Tips When Using `#!/usr/bin/env bash` {#sec-e5a739214684} ### 1) How to Execute the Script {#sec-83e5cc5b64a5} To properly leverage shebang, instead of just doing this: ```bash bash script.sh # ← Executing this way largely ignores the shebang ``` it's better to use it as follows: ```bash chmod +x script.sh # Grant execute permission ./script.sh # Execute directly ``` This way, the kernel reads `#!` and uses the specified interpreter. ### 2) Checking Argument Passing {#sec-90ca3c9235bf} For example, let's say you create `test.sh` as follows. ```bash #!/usr/bin/env bash echo "Interpreter: $0" echo "Arguments: $@" ``` Execution: ```bash chmod +x test.sh ./test.sh hello world ``` Output: ```text Interpreter: ./test.sh Arguments: hello world ``` Here, `$0` is "the script file's own path", and you just need to remember that the kernel is actually executing it like `/usr/bin/env bash test.sh hello world`. --- ## 8. Frequently Asked Questions {#sec-99b0325925f3} ### I've seen scripts written without a shebang. Why is that? {#sec-751234a46d29} * That's correct, **it's not always necessary.** * If you explicitly specify the interpreter for execution as shown below, a shebang is not needed. Even if a shebang is present, it will be ignored. ```bash bash myscript.sh python3 myscript.py ``` * However, if you want to execute it like this, it is absolutely necessary. ```bash ./myscript.sh ./myscript.py ``` * Especially for "tool-like" scripts that others might use, **a shebang is almost essential**. ### "I've seen `#!/bin/env` used instead of `#!/usr/bin/env`. Is that also valid?" {#sec-6de89a827da4} * Some systems might have `/bin/env`. * However, `/usr/bin/env` is generally a much more common standard location. * Unless there's a specific reason, using `#!/usr/bin/env …` is safer. --- ## 9. Summary {#sec-971578a5a9d1} * `#!/usr/bin/env bash` or `#!/bin/bash` is **not a comment, but an instruction to the kernel telling it 'which interpreter to use to execute this script'**. * `#!/bin/bash` * Always uses `/bin/bash` → **Predictable in fixed environments, but may not be portable** * `#!/usr/bin/env bash` * Finds bash in `PATH` → **More flexible and portable, but affected by PATH status** * For general development/deployment environments, if you're writing scripts in a 'modern style', **using `#!/usr/bin/env bash` as the default** can be recommended. ![image of shebang in linux script](https://blog.mikihands.com/media/editor_temp/6/692ed85d-0eb6-4fd1-ab7a-22a2d189175d.png "Image illustrating shebang's operating principle")