# Shebang Lines Explained: Why #!/bin/bash Matters

By the end of this article you will be able to read any shebang line and say exactly what it does, write a bioinformatics shell script that launches correctly with `./script.sh`, choose between `#!/bin/bash` and `#!/usr/bin/env bash` for your own system, and diagnose the four or five errors that account for almost every shebang problem you will ever hit on a laptop, a server, or a high-performance computing (HPC) cluster.

To follow the walkthrough you need a terminal with bash available. That means any Linux desktop or server, macOS (which ships bash), or Windows with Windows Subsystem for Linux 2 (WSL2) installed. You also need a plain-text editor such as nano, vim, or VS Code. Two optional tools make debugging easier: `dos2unix`, available in every major package manager, and `shellcheck`, a static analyzer for shell scripts.

The context for this is simple. Bioinformatics is command-line work. Universities now teach bash programming directly to biologists because genomic data analysis depends on it [1]. Published pipelines are shipped as bash scripts that run on local machines or through batch schedulers [2], and even specialized pipelines for multi-device electrophysiology data are described as command-line bash pipelines [3]. The shebang line is the first line of nearly all of those scripts, and it is the line that decides whether the script runs at all.

## What a Shebang Line Is

A shebang line is the first line of an executable text file, and it always starts with the two characters `#!`. The `#` character is called a sharp or hash, the `!` is called a bang, so `#!` became known as the shebang, the hashbang, or the sharp-bang. After those two characters you write the absolute path to the program that should interpret the rest of the file.

The most common forms look like this:

```
#!/bin/bash
#!/usr/bin/env bash
#!/bin/sh
#!/usr/bin/env python3
```

Each line names an interpreter. `#!/bin/bash` says the file should be run by bash, the Bourne Again Shell, the default interactive shell on most Linux distributions. `#!/usr/bin/env bash` says the file should be run by whichever bash the system finds first in the user's `PATH`, the ordered list of directories the shell searches for commands. `#!/bin/sh` requests the POSIX shell, a leaner and more portable program that lacks some bash features. The last example shows the same mechanism works for Python, R, Perl, and any other scripting language.

Three rules govern the shebang, and all three are enforced by the operating system rather than by bash:

1. The shebang must occupy the very first line of the file. The first two bytes of the file must be `#` (hexadecimal 0x23) followed by `!` (hexadecimal 0x21). A blank line, a byte order mark, or a comment above it breaks the mechanism entirely.
2. The interpreter path must be absolute. `#!/bin/bash` works, `#!bash` does not, because the kernel resolves the path directly rather than searching your `PATH`.
3. On Linux, everything after the interpreter path is passed to it as a single optional argument. This limits what you can put on the shebang line, a constraint covered in detail below.

Everything after the shebang line is ordinary script content. Inside bash, the `#` character also begins a comment, so if you accidentally run a script by passing it to bash directly, as in `bash script.sh`, the shebang line is simply ignored as a comment. The shebang only does its job when the operating system itself loads the file, which happens when you execute it as `./script.sh` or from another program.

## How Linux Decides What Runs a Script

The mechanism lives in the kernel, the core program of the operating system that starts every process. When you type `./count_reads.sh` and press Enter, the shell calls the `execve` system call, asking the kernel to replace the current process with the program stored in that file. The kernel reads the first bytes of the file. If those bytes are a recognized binary format, such as an ELF executable, the kernel loads it directly. If the first two bytes are `#!`, the kernel treats the file as a script, parses the interpreter path and optional argument from the first line, and executes that interpreter instead, handing it the path to your script as an argument.

If the file starts with neither a binary signature nor `#!`, the kernel returns the error code `ENOEXEC`. In practice you rarely see that raw error, because your shell catches it and falls back to interpreting the file itself as a shell script. That fallback is why shebang-less scripts sometimes appear to work and then fail mysteriously on a different machine, where the login shell is `sh` or zsh instead of bash.

You can observe the mechanism directly with a two-line experiment that requires no bioinformatics tools. The `echo` program prints its arguments, so if a script declares `echo` as its interpreter, executing the script will make the kernel run `echo` with the script path as the argument:

```
printf '#!/bin/echo\necho this line is data\n' > demo_script
chmod +x demo_script
./demo_script
```

The output is:

```
./demo_script
```

The line `echo this line is data` was never executed. The kernel read the shebang, launched `/bin/echo`, and passed `./demo_script` to it as an argument. `echo` printed that argument and exited. This single experiment demonstrates the entire contract: the interpreter named on the first line receives your file, and everything else follows from that.

This also explains the difference between two ways of running a script. When you type `./count_reads.sh`, the kernel reads the shebang and launches the interpreter named there. When you type `bash count_reads.sh`, you have already chosen the interpreter, so the kernel is not consulted about it, and the shebang line is read as an ordinary comment. Both work when the shebang is correct. Only the second works when the shebang is wrong, which is why `bash script.sh` is a common workaround and also why it hides shebang bugs until the script is moved to a scheduler or handed to a collaborator.

## Step-by-Step: A Working Bioinformatics Script

The walkthrough below builds a small but genuinely useful tool for FASTQ data. FASTQ is the standard text format for raw sequencing reads, and it stores each read as four consecutive lines: a header beginning with `@`, the sequence, a separator line beginning with `+`, and the quality scores. Counting reads therefore means counting lines and dividing by four. The script handles gzipped FASTQ, the standard storage format, and reports the read count.

### Step 1. Create a working directory

```
mkdir -p ~/bin
cd ~/bin
```

The `-p` flag tells `mkdir` to create the full path and to stay silent if the directory already exists, which prevents an error when you rerun the command.

### Step 2. Write the script with its shebang

Type this into a file named `count_reads.sh`, either in your editor or by pasting the whole block into the terminal:

```
cat > count_reads.sh <<'EOF'
#!/bin/bash
set -eu

# count_reads.sh: count reads in a gzipped FASTQ file
# usage: ./count_reads.sh sample.fastq.gz

if [ $# -ne 1 ]
then
  echo "Usage: $0 sample.fastq.gz" >&2
  exit 1
fi

lines=$(gzip -dc "$1" | wc -l)
reads=$((lines / 4))
echo "$reads reads in $1"
EOF
```

The heredoc syntax `cat > file <<'EOF'` writes everything between the markers into the file, and the quoted `'EOF'` prevents the shell from expanding variables while writing. Inside the script, `set -eu` turns on two safety behaviors: `-e` makes the script stop on the first failed command, and `-u` makes it fail if you reference an unset variable. The `if` block checks that exactly one argument was supplied, where `$#` holds the argument count and `$0` holds the script name. `gzip -dc` decompresses to standard output, `wc -l` counts lines, and the arithmetic expansion `$((lines / 4))` converts lines to reads.

Note where the shebang sits. It is the first line, with nothing above it, and it is followed by `set -eu` on its own line. That ordering is mandatory.

### Step 3. Make the script executable

```
chmod +x count_reads.sh
```

The `chmod` command changes file mode bits, and `+x` adds execute permission for the owner. Without this step the kernel refuses to run the file at all, regardless of how correct the shebang is.

### Step 4. Run it

```
./count_reads.sh sample.fastq.gz
```

On a small test file with 10,000 reads, the expected output is:

```
10000 reads in sample.fastq.gz
```

If you omit the argument, you get the usage message:

```
Usage: ./count_reads.sh sample.fastq.gz
```

The `>&2` in the script sends that message to standard error, the conventional channel for diagnostics, so it stays separate from any data the script might print.

### Step 5. Verify the shebang is correct

Two checks confirm the file is well-formed. The first reads the first line:

```
head -1 count_reads.sh
```

Expected output:

```
#!/bin/bash
```

The second inspects the raw bytes, which is the definitive test because it reveals invisible characters such as carriage returns:

```
head -1 count_reads.sh | od -c
```

Expected output:

```
0000000   #   !   /   b   i   n   /   b   a   s   h  \n
0000013
```

Each visible character between the `#` and the newline (`\n`) should be exactly what you expect, with no `\r` characters anywhere. The octal number `0000013` is the byte offset in octal notation, confirming the line is 11 bytes long.

### Step 6. Confirm the interpreter path exists on your machine

```
command -v bash
```

On a typical Ubuntu or Debian server this prints:

```
/usr/bin/bash
```

On many other systems it prints `/bin/bash`. On modern Debian and Ubuntu releases, `/bin` is a symbolic link into `/usr/bin`, so both paths resolve to the same program, and `#!/bin/bash` works even though the real file lives under `/usr/bin`. On FreeBSD, bash commonly lives at `/usr/local/bin/bash`, which is exactly the situation where a hardcoded `/bin/bash` shebang fails and the `env` form saves you, as described next.

### Step 7. Compare the two invocation styles

```
bash count_reads.sh sample.fastq.gz
./count_reads.sh sample.fastq.gz
```

Both produce identical output on this machine because the shebang and the explicit `bash` command agree. The difference appears when the shebang is wrong or missing. To see it, temporarily change the first line to `#!/bin/doesnotexist`, then run both forms. The direct execution fails with the kernel-level error, while `bash count_reads.sh` succeeds, because bash ignores the broken shebang as a comment. Restore the correct line afterward. This contrast is the fastest way to convince yourself that the shebang matters only when the operating system, rather than your typing, selects the interpreter.

If you point the script at an uncompressed FASTQ by mistake, `gzip` reports it precisely:

```
gzip: sample.fastq: not in gzip format
```

Because `set -e` is active, the script stops there instead of printing a nonsense read count, which is exactly the behavior you want in a pipeline component.

## Choosing the Right Interpreter Line

The four common shebangs differ in portability, features, and failure modes. The table below summarizes the choice, and the paragraphs after it explain the details that the table cannot fit.

| Shebang | Interpreter actually used | Works reliably on | Use when |
|--|--|--|--|
| `#!/bin/bash` | Bash at the fixed path `/bin/bash` | Linux distributions where bash sits at `/bin/bash` | Your script uses bash features and targets standard Linux servers |
| `#!/usr/bin/bash` | Bash at `/usr/bin/bash` | Distributions with merged `/usr`, such as Fedora and Arch | Rarely, and only when you know the path |
| `#!/usr/bin/env bash` | The first `bash` found in the user's `PATH` | Linux, macOS, BSD, conda environments, most HPC clusters | Scripts shared across machines or used inside conda environments |
| `#!/bin/sh` | The POSIX shell, which is `dash` on Debian and Ubuntu | Everywhere, by POSIX convention | Simple, portable scripts that avoid bash-only features |

The `env` form deserves a longer explanation, because it is the one you will most often be told to use and least often be told why. The `env` program executes a named command by searching `PATH`, rather than requiring a fixed location. This matters in three real situations. On macOS, bash lives at `/bin/bash`, so `#!/bin/bash` works, but other tools such as Python live under `/usr/bin` or Homebrew paths, and `env` sidesteps the guessing. On FreeBSD, bash installs to `/usr/local/bin/bash`, where `#!/bin/bash` simply fails. Inside a conda environment on an HPC cluster, activating the environment prepends its `bin` directory to `PATH`, so `#!/usr/bin/env bash` picks up the environment's bash while `#!/bin/bash` picks up the system's, and the two may differ in version and available features.

The trade-off is that `env` depends on `PATH`, and `PATH` depends on context. Under `cron`, in some Slurm configurations, and in stripped-down container runtimes, `PATH` can be minimal, and `env` can then fail to find bash at all. For scripts that run only on one well-characterized Linux server, the fixed `#!/bin/bash` is deterministic and safe. For scripts you distribute, the `env` form is usually the better default.

The `#!/bin/sh` line is a different tool for a different job. On Debian and Ubuntu, `/bin/sh` is a symbolic link to `dash`, a shell that runs faster than bash but lacks bash extensions, collectively called bashisms. Common bashisms include arrays declared as `reads=(sampleA sampleB)`, the extended test syntax `[[ ]]`, and process substitution written as `<(command)`. If a script using an array carries `#!/bin/sh` and runs on Ubuntu, dash stops with:

```
Syntax error: "(" unexpected
```

The fix is to change the shebang to a bash form, because the script genuinely needs bash. The reverse mistake, writing `#!/bin/bash` on a script that uses only POSIX constructs, costs a little startup time and nothing else, which is why bash is the pragmatic default for bioinformatics work.

## Flags in the Shebang Line

Because the kernel passes everything after the interpreter path as a single argument, you can set shell options on the shebang, but only within that limit. These two lines behave differently:

```
#!/bin/bash -eu
```

works, because `-eu` is one argument that turns on both the `-e` (exit on error) and `-u` (error on unset variable) options. This line does not work as intended:

```
#!/bin/bash -e -u
```

Here the kernel passes the single argument `-e -u` to bash, which cannot parse it as two flags. The same constraint affects the `env` form. The line `#!/usr/bin/env bash -eu` fails on older systems with:

```
env: 'bash -eu': No such file or directory
```

because `env` searches for a command literally named `bash -eu`. GNU coreutils version 8.30 and later solve this with the `-S` option, which splits a single string into separate arguments, giving the portable modern form:

```
#!/usr/bin/env -S bash -eu
```

A practical recommendation is to skip flags on the shebang entirely and state options on the first lines of the script body, where they are visible, editable, and independent of kernel parsing quirks:

```
#!/usr/bin/env bash
set -euo pipefail
```

The `-o pipefail` option makes a pipeline return failure if any stage fails, not just the last one, which matters when you pipe decompression into counting or alignment into sorting. A failed decompression step that went unnoticed would otherwise produce a silently truncated result.

## Why This Matters for Bioinformatics Workflows

Published bioinformatics software makes the point concretely. PePApipe, a pipeline for African Swine Fever Virus [genome analysis](/blog/guides/genome-analysis) that integrates thirteen tools from raw reads through consensus calling, is programmed in Python and executed locally through bash scripts or through Slurm for batch processing of multiple samples [2]. Every one of those entry points begins with a shebang line, and a wrong one stops the pipeline before any of the thirteen tools runs. CASCADE, a cross-platform analysis engine for multi-electrode array recordings from five manufacturers, is likewise a Python-based command-line bash pipeline [3]. The training literature makes the same point from the other direction, since cloud-based modules introducing bash programming for biologists are built specifically because genomic data analysis requires it [1].

The reproducibility literature adds a subtler lesson. The admixr package was created because traditional ADMIXTOOLS workflows required users to generate configuration files through a combination of shell scripting and manual text editing, and unifying those steps under a single framework improved reproducibility [4]. The generalizable point is that ad hoc shell glue is where reproducibility most often breaks, and the first step toward controlled shell glue is a script that reliably invokes the interpreter you intended, on every machine and every scheduler, which is precisely what a correct shebang guarantees.

Slurm deserves a specific note because it is the most common batch scheduler in genomics. A Slurm submission script is itself a shell script with a shebang on line one, followed by scheduler directives on lines beginning with `#SBATCH`, which specify the job name, partition, memory, time limit, and module loads. If the shebang is missing or wrong, Slurm may submit the job successfully and then run it under a different shell than you designed for, producing errors that appear only inside the batch environment and never in your interactive testing. The rule is mechanical: shebang first, directives second, commands third.

## Diagnosing the Errors You Will Actually See

Almost every shebang failure falls into one of six patterns. Learning to recognize the exact messages turns a frustrating afternoon into a thirty-second fix.

### The carriage return error

```
bash: ./count_reads.sh: /bin/bash^M: bad interpreter: No such file or directory
```

The `^M` is the visible form of a carriage return character. Windows text editors end lines with a carriage return followed by a line feed, the CRLF convention, while Linux expects only a line feed, the LF convention. The kernel therefore looks for an interpreter named `/bin/bash\r`, which does not exist. Confirm the diagnosis with:

```
file count_reads.sh
```

A Windows-authored file reports:

```
count_reads.sh: Bourne-Again shell script, ASCII text executable, with CRLF line terminators
```

Fix it with either command:

```
dos2unix count_reads.sh
sed -i 's/\r$//' count_reads.sh
```

The `sed` command substitutes an empty string for a carriage return at the end of each line, editing the file in place with `-i`. The permanent fix is to configure your editor to save with LF line endings for shell scripts.

### The permission error

```
bash: ./count_reads.sh: Permission denied
```

The file exists, the shebang is fine, but no execute bit is set. Fix it with `chmod +x count_reads.sh` and confirm with `ls -l count_reads.sh`, which should show `x` characters in the permission string, as in `-rwxr-r-`.

### The missing interpreter error

```
bash: ./count_reads.sh: /bin/bash: bad interpreter: No such file or directory
```

Here there is no `^M`, which means the path itself is the problem. This occurs in minimal Docker images, such as Debian slim variants that ship without bash, and on systems such as FreeBSD where bash sits at `/usr/local/bin/bash`. Either install bash, switch the shebang to `#!/bin/sh` for a POSIX-compatible script, or use the `env` form so the interpreter is found through `PATH`.

### The wrong shell error

A script with `#!/bin/sh` that uses bashisms fails on Debian and Ubuntu with messages such as:

```
./count_reads.sh: 7: Syntax error: "(" unexpected
```

The `7` is the line number where dash gave up. The fix is a bash shebang, since the script requires bash features.

### The empty PATH error

```
env: bash: No such file or directory
```

This appears when a script with `#!/usr/bin/env bash` runs under `cron` or certain Slurm configurations where `PATH` is minimal and does not include any directory containing bash. Fix it by hardcoding the shebang for that environment, or by setting `PATH` explicitly on the early lines of the script.

### The displaced shebang

If the shebang sits on line two because a blank line or a comment was inserted above it, the kernel no longer sees `#!` as the first two bytes. Execution then falls through to the shell fallback described earlier, and the symptoms vary with the caller's shell. The same happens when an editor saves a file with a byte order mark, a few invisible bytes that some editors add at the start of UTF-8 files. The diagnostic is the byte-level check from Step 5, and the fix is to delete everything above the shebang and re-save with LF line endings and no byte order mark.

## Verifying Your Work

A short verification routine catches all of the above before anyone runs the script. Check the first line and its bytes, confirm the execute bit, parse the syntax, and lint the logic:

```
head -1 count_reads.sh
head -1 count_reads.sh | od -c
ls -l count_reads.sh
bash -n count_reads.sh
shellcheck count_reads.sh
```

The `bash -n` flag asks bash to read the script and report syntax errors without executing anything, which is safe to run on any script including ones that submit jobs or delete files. `shellcheck` goes further and flags unquoted variables, useless constructs, and portability problems, and it is available in every major Linux package repository. A script that passes all five checks will start correctly on any Linux machine where its named interpreter exists, which is the practical definition of a portable bioinformatics script.

## Shebang and Scripting Tips for Bioinformatics Work

These habits separate scripts that work once from scripts that work for years.

1. Start every script with a shebang, even scripts you always invoke with an explicit `bash` command. The habit costs nothing and removes a whole class of failure when a collaborator, a scheduler, or a workflow manager invokes the script directly.
2. Follow the shebang with `set -euo pipefail` on its own line in bash scripts, so failures surface immediately rather than propagating as silent corrupt data.
3. Quote every variable expansion, as in `"$1"` and `"$reads"`, because file paths with spaces are common when collaborators upload data from other operating systems.
4. Test on a small input first. A script that counts reads correctly on a 10,000-read test file has verified every code path except runtime, which is where parallelization and memory problems live.
5. Keep scripts in a version-controlled repository alongside the commands that installed each tool and its version. Scripted, version-controlled analysis steps are the mechanism by which frameworks such as admixr improve reproducibility in population genetic studies [4], and the same principle applies to any pipeline.
6. When a script must run under a scheduler, run it once interactively with the same interpreter the scheduler will use, because a scheduler's environment differs from a login shell in `PATH`, loaded modules, and working directory.
7. Prefer `#!/usr/bin/env bash` for scripts you distribute and `#!/bin/bash` for scripts tied to one known server. Choosing deliberately, with the trade-offs above in mind, beats either default used blindly.

## Common Mistakes and Limitations

The following mistakes account for nearly all shebang trouble in practice, and each has appeared somewhere in the walkthrough above.

1. Editing scripts on Windows without converting line endings, producing the `bad interpreter` error with `^M` the first time the script runs on Linux. Set the editor to LF, or run `dos2unix` as part of your routine.
2. Forgetting `chmod +x` and then concluding the shebang is broken, when the actual error is `Permission denied` and the fix is one command.
3. Placing the shebang on the second line, below a comment, an import banner, or a byte order mark. The kernel reads only the first two bytes, so anything above the shebang disables the mechanism.
4. Using `#!/bin/sh` on a script that uses arrays, `[[ ]]`, or other bashisms, which works on some machines and fails on dash-based systems with a syntax error at the first bash-only construct.
5. Assuming `PATH` is the same everywhere. The `env` shebang resolves through `PATH`, and `PATH` under `cron`, Slurm, and container runtimes is frequently minimal. Scripts that run interactively can fail in batch precisely because of this.
6. Mixing flags into the shebang as if the kernel parsed multiple arguments. Linux passes everything after the interpreter as one argument, so `#!/bin/bash -e -u` fails while `#!/bin/bash -eu` works, and `env` needs `-S` for anything beyond the interpreter name.
7. Debugging with `bash script.sh`, which bypasses the shebang entirely and hides the bug until the script is used the intended way.
8. Treating the shebang as a substitute for testing. A correct shebang guarantees the right interpreter starts. It guarantees nothing about the logic after line one, which is what `bash -n`, `shellcheck`, and a small test dataset are for.

One limitation frames all of the above. Cluster and server environments differ in where interpreters live, how modules are loaded, and how schedulers construct the job environment, so the correct shebang for your local cluster should be confirmed against its own documentation, and the verification routine in this article is the fastest way to do that.

## Frequently Asked Questions

### What does #!/bin/bash actually do?

It tells the operating system kernel to run the file using the bash interpreter located at `/bin/bash`. When you execute the script directly, the kernel reads the first two bytes, sees `#!`, launches `/bin/bash`, and passes your script to it as an argument.

### What is the difference between #!/bin/bash and #!/usr/bin/env bash?

`#!/bin/bash` requires bash at exactly that path, while `#!/usr/bin/env bash` finds bash wherever it appears first in your `PATH`. The fixed path is deterministic on one machine, and the `env` form is more portable across macOS, BSD, and conda environments.

### Can a script run without a shebang line?

Yes, in two ways. If you invoke it explicitly with `bash script.sh`, the shebang is unnecessary because you chose the interpreter. If you execute it directly, the kernel returns a non-executable error and your current shell usually reinterprets the file itself, which means the script's behavior depends on whoever launched it.

### Why does my script say bad interpreter with ^M in the message?

The `^M` is a carriage return character from Windows-style CRLF line endings, so the kernel is searching for an interpreter named `/bin/bash\r`. Convert the file with `dos2unix` or `sed -i 's/\r$//' script.sh` and set your editor to save LF line endings.

### Does a shebang work on macOS and Windows?

Shebangs work on macOS, which ships bash at `/bin/bash`, and they work inside WSL2 on Windows, which is a real Linux environment. They do not work in the Windows command prompt or PowerShell, where scripts are executed by other mechanisms entirely.

### Can I put flags like -e in the shebang line?

Yes, with limits. Linux passes everything after the interpreter path as a single argument, so `#!/bin/bash -eu` works and `#!/bin/bash -e -u` does not. With the `env` form you need GNU coreutils 8.30 or later and the syntax `#!/usr/bin/env -S bash -eu`, though writing `set -euo pipefail` inside the script is usually clearer.

### Where exactly must the shebang be placed?

On the very first line, as the first two bytes of the file, with an absolute interpreter path and nothing above it. A blank line, a comment, or a byte order mark above the shebang disables the mechanism entirely.

### Do I need a shebang if I always run scripts with bash script.sh?

You do not need it for yourself, but you need it for everyone and everything else, including batch schedulers, workflow managers, and collaborators. Slurm submission scripts in particular require a correct shebang so the job runs under the shell you designed for.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "What does #!/bin/bash actually do?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "It tells the operating system kernel to run the file using the bash interpreter located at /bin/bash. When you execute the script directly, the kernel reads the first two bytes, sees #!, launches /bin/bash, and passes your script to it as an argument."
      }
    },
    {
      "@type": "Question",
      "name": "What is the difference between #!/bin/bash and #!/usr/bin/env bash?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "#!/bin/bash requires bash at exactly that path, while #!/usr/bin/env bash finds bash wherever it appears first in your PATH. The fixed path is deterministic on one machine, and the env form is more portable across macOS, BSD, and conda environments."
      }
    },
    {
      "@type": "Question",
      "name": "Can a script run without a shebang line?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Yes, in two ways. If you invoke it explicitly with bash script.sh, the shebang is unnecessary because you chose the interpreter. If you execute it directly, the kernel returns a non-executable error and your current shell usually reinterprets the file itself, which means the script's behavior depends on whoever launched it."
      }
    },
    {
      "@type": "Question",
      "name": "Why does my script say bad interpreter with ^M in the message?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "The ^M is a carriage return character from Windows-style CRLF line endings, so the kernel is searching for an interpreter named /bin/bash followed by a carriage return. Convert the file with dos2unix or sed -i 's/\\r$//' script.sh and set your editor to save LF line endings."
      }
    },
    {
      "@type": "Question",
      "name": "Does a shebang work on macOS and Windows?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Shebangs work on macOS, which ships bash at /bin/bash, and they work inside WSL2 on Windows, which is a real Linux environment. They do not work in the Windows command prompt or PowerShell, where scripts are executed by other mechanisms entirely."
      }
    },
    {
      "@type": "Question",
      "name": "Can I put flags like -e in the shebang line?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Yes, with limits. Linux passes everything after the interpreter path as a single argument, so #!/bin/bash -eu works and #!/bin/bash -e -u does not. With the env form you need GNU coreutils 8.30 or later and the syntax #!/usr/bin/env -S bash -eu, though writing set -euo pipefail inside the script is usually clearer."
      }
    },
    {
      "@type": "Question",
      "name": "Where exactly must the shebang be placed?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "On the very first line, as the first two bytes of the file, with an absolute interpreter path and nothing above it. A blank line, a comment, or a byte order mark above the shebang disables the mechanism entirely."
      }
    },
    {
      "@type": "Question",
      "name": "Do I need a shebang if I always run scripts with bash script.sh?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "You do not need it for yourself, but you need it for everyone and everything else, including batch schedulers, workflow managers, and collaborators. Slurm submission scripts in particular require a correct shebang so the job runs under the shell you designed for."
      }
    }
  ]
}
</script>

## Sources

1. [Cloud-based introduction to BASH programming for biologists.](https://pubmed.ncbi.nlm.nih.gov/39041911/)
2. ['PePApipe': A complete bioinformatics analysis pipeline for African Swine Fever Virus genome.](https://pubmed.ncbi.nlm.nih.gov/42721146/)
3. [CASCADE: criticality avalanche spike cross-platform analysis detection engine, a multi-manufacturer MEA bash analysis pipeline.](https://pubmed.ncbi.nlm.nih.gov/42525390/)
4. [admixr-R package for reproducible analyses using ADMIXTOOLS.](https://pubmed.ncbi.nlm.nih.gov/30668635/)