Shell script working fine without shebang line? Why?

The POSIX (Single UNIX Specification 4) standard is not helpful:

If the first line of a file of shell commands starts with the characters "#!" , the results are unspecified.

So, the standard implies that if you don't have #! then it should run a POSIX shell. But modern shells are not POSIX compliant. The old Korn Shell 88 (ksh88) ran the Bourne shell (close to a POSIX shell) with no #! line, but ksh93 breaks that, and so does Bash. With both ksh93 and Bash, they run their own shell if no #! line is present.

Despite popular opinion, Bash and Korn shells differ. When you write a shell script you can never be sure what shell you will be run from, or even if it will be run from another shell at all (most programming languages can run other programs). The minute you use something outside of Bourne/POSIX syntax you will be scuppered.

Always use a #! line, don't leave it to chance.


The parent shell, where you entered ./myscript.sh, first tried to execve it, which is where the shebang line would take effect if present. When this works, the parent is unaware of the difference between scripts and ELFs because the kernel takes care of it.

The execve failed, so an ancient unix compatibility feature, predating the existence of shebang lines, was activated. It guessed that a file which has execute permission but is not recognized as a valid executable file by the kernel must be a shell script.

Usually the parent shell guesses that the script is written for the same shell (minimal Bourne-like shells run the script with /bin/sh, bash runs it as a bash subprocess), csh does some more complicated guessing based on the first character because it predates shebang too and it needed to coexist with Bourne shell).

You need a shebang line when you know these guesses will be wrong (for example with the shebang is #!/usr/bin/perl), or when you don't trust the guessing to work consistently, or when the script needs to be runnable by a parent process that is not a shell itself.


shebang line is needed in the file and only if it's meant to be run as executable (as opposed to sh file.sh invocation. It is not actually needed by script, it is for the system to know how to find interpreter.

EDIT: Sorry for misreading the question. If the shebang line is missing or not recognized, /bin/sh is used. But I prefer being explicit about the interpreter.

Note, that this behavior is not universal, IIRC, only some exec* family function do that (not to mention different platforms), so that's another reason to be explicit here.