Skip to content

What Is a Shebang Line? How the #! Tells Your System Which Interpreter to Use

Sep 19, 2026 · Tooling

A shebang line is the first line of a script, beginning with the characters #!, that tells the operating system which interpreter should run the file. When you execute a script directly, the kernel reads these first two bytes, finds the interpreter path that follows, and launches that program with the script as its input. This is what lets a text file behave like a runnable command, so you can type ./deploy.sh instead of bash deploy.sh. The name comes from the sharp (#) and bang (!) symbols.

Key takeaways

  • The shebang #! must be the first two bytes of the file to work.
  • It names the interpreter that runs the script, e.g. #!/bin/bash.
  • It only matters when the file is executed directly and marked executable.
  • #!/usr/bin/env python3 is more portable than a hardcoded path.
  • The file also needs the executable permission bit set with chmod +x.
  • Windows carriage-return line endings are a frequent cause of failures.

How does the shebang line work?

When you run a file directly, the kernel inspects its first bytes. If they are #!, the kernel treats the rest of that line as the path to an interpreter, then runs that interpreter and hands it the script file as an argument. Effectively, executing ./script becomes running /interpreter/path ./script behind the scenes.

A minimal example:

#!/bin/bash
echo "Hello from bash"

Two conditions must both hold for this to take effect: the shebang is on the first line, and the file has the executable bit set. Without the executable bit the shell reports a permission error; without the shebang the kernel does not know which interpreter to use.

It helps to know what happens when there is no shebang. If you try to execute a plain text file with no #!, the kernel cannot load it as a program and reports an executable-format error. Many shells then fall back to running the file with the current shell, which is why a shebang-less shell script sometimes appears to work but fails the moment a different shell or a language like Python is expected. Relying on that fallback is fragile; an explicit shebang removes the guesswork and makes the script behave the same no matter what launched it.

How do I make a script executable and run it?

Add the executable permission and then run the file by path:

chmod +x script.sh
./script.sh

The leading ./ matters: it tells the shell to run the file in the current directory rather than searching PATH. If the file is in a directory on your PATH, you can invoke it by name alone.

Why use /usr/bin/env instead of a hardcoded path?

The interpreter you want is not always in the same location on every system. A Python installation might live at /usr/bin/python3 on one machine and elsewhere on another, especially inside virtual environments. Hardcoding the path makes the script fragile.

The env program solves this by searching PATH for the named interpreter:

#!/usr/bin/env python3
print("portable")

Because env itself reliably lives at /usr/bin/env across systems, this pattern finds whichever python3 is first on the user’s PATH, including one activated in a virtual environment. The trade-off is a small loss of control, since you no longer pin an exact interpreter path.

What are the common shebang forms?

Shebang Runs the script with Notes
#!/bin/sh The system POSIX shell Most portable for shell scripts
#!/bin/bash Bash specifically Needed for Bash-only features
#!/usr/bin/env python3 First python3 on PATH Portable across installs
#!/usr/bin/env node First node on PATH Common for CLI tools
#!/usr/bin/perl Perl at a fixed path Simple but less portable

Choose #!/bin/sh when your script uses only portable shell syntax, and reserve #!/bin/bash for scripts that rely on Bash extensions such as arrays or [[ ]] tests.

What are the limits on passing arguments in a shebang?

You can usually pass one argument to the interpreter, but not many. For example:

#!/bin/bash -e

This asks Bash to exit on the first error. The catch is that many kernels treat everything after the interpreter path as a single argument, so #!/usr/bin/env python3 -O may fail because python3 -O is passed as one string that env cannot find. When you need interpreter flags portably, set them inside the script instead of in the shebang.

Some newer versions of env add a -S option that splits the remaining text into separate arguments, allowing forms like #!/usr/bin/env -S python3 -O. Because that option is not available everywhere, it is safe only when you control the target systems. The dependable, universal approach remains to keep the shebang minimal and configure interpreter behavior from within the script, for example by enabling shell options with set on the first executable line rather than in the shebang itself.

Why does the # not break the script?

In shells, Python, Ruby, Perl, and many other languages the # character begins a comment. So when the interpreter later reads the file itself, it sees the shebang line as an ordinary comment and ignores it. The line therefore serves two audiences at once: the kernel reads it as an instruction, and the interpreter reads it as a harmless comment. This dual role is why the same first line works whether the kernel or the interpreter is reading it.

How do different systems and languages treat the shebang?

The shebang is a convention of Unix-like kernels, so its behavior varies by environment. Knowing where it applies prevents a lot of cross-platform confusion.

  • Linux and macOS honor the shebang directly in the kernel when a file is executed.
  • Native Windows ignores it, because the Windows loader selects programs by file extension and association rather than by file content. Compatibility layers such as WSL, Git Bash, and Cygwin restore shebang behavior.
  • Language launchers add their own twists. The Windows Python launcher, for instance, reads the shebang text to pick a Python version even though the OS does not.

A subtle portability note: some systems cap the shebang line length, so very long interpreter paths can be silently truncated. Keep the path short, and prefer the env form so the interpreter is resolved by name. When a script must run identically on Windows and Unix, either provide a wrapper for each platform or use a language whose launcher understands the shebang, rather than assuming the OS will.

What are common shebang mistakes and pitfalls?

  • Windows line endings. A carriage return at the end of the shebang line becomes part of the interpreter path, producing a confusing bad interpreter error. Save scripts with Unix line endings.
  • A blank line before the shebang. The kernel only checks the very first bytes, so any preceding content disables it.
  • Missing executable bit. Without chmod +x the file cannot be run directly regardless of the shebang.
  • Wrong interpreter path. Hardcoding a path that does not exist on the target system breaks the script; prefer the env form for portability.
  • Spaces in the path. Interpreter paths with spaces are not handled reliably across systems.

Frequently asked questions

Does the shebang line work on Windows?

Native Windows does not honor the shebang, since the kernel does not use it to select an interpreter. Environments like WSL, Git Bash, and Cygwin do respect it.

Why must the shebang be the very first line?

The kernel only checks the first two bytes of a file for #!. If anything, even a blank line or comment, precedes it, the shebang is ignored.

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

The first hardcodes an absolute path; the second searches PATH for bash, which is more portable across systems where the interpreter lives in different locations.

Do I still need a shebang if I run the script with an interpreter?

No. If you run python script.py the interpreter is chosen explicitly, so the shebang is ignored. It only matters when you execute the file directly.

Can I pass arguments to the interpreter in a shebang?

You can pass at most one argument reliably, because many systems treat everything after the interpreter path as a single argument. The env trick has additional limits.

Why does my script say ‘bad interpreter’?

Usually the interpreter path is wrong, or the file has Windows carriage-return line endings that make the path invalid. Convert line endings to Unix format.

Is the shebang a comment?

In many scripting languages the # makes the line a comment, so the interpreter ignores it. The kernel, however, reads it as an instruction, so it serves both roles.

Frequently asked questions

Does the shebang line work on Windows?

Native Windows does not honor the shebang, since the kernel does not use it to select an interpreter. Environments like WSL, Git Bash, and Cygwin do respect it.

Why must the shebang be the very first line?

The kernel only checks the first two bytes of a file for #!. If anything, even a blank line or comment, precedes it, the shebang is ignored.

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

The first hardcodes an absolute path; the second searches PATH for bash, which is more portable across systems where the interpreter lives in different locations.

Do I still need a shebang if I run the script with an interpreter?

No. If you run python script.py the interpreter is chosen explicitly, so the shebang is ignored. It only matters when you execute the file directly.

Can I pass arguments to the interpreter in a shebang?

You can pass at most one argument reliably, because many systems treat everything after the interpreter path as a single argument. The env trick has additional limits.

Why does my script say 'bad interpreter'?

Usually the interpreter path is wrong, or the file has Windows carriage-return line endings that make the path invalid. Convert line endings to Unix format.

Is the shebang a comment?

In many scripting languages the # makes the line a comment, so the interpreter ignores it. The kernel, however, reads it as an instruction, so it serves both roles.

Contact: contact@quikconsolecom.net