The two characters that tell the kernel what to do
When you run ./script.sh, the kernel reads the first two bytes. If they're #! (the shebang), the rest of the first line is the path to an interpreter. The kernel runs that interpreter with your script as the argument.
The portable shape
#!/usr/bin/env bash
#!/usr/bin/env zsh
#!/usr/bin/env python3
#!/bin/sh/usr/bin/env looks the binary up on PATH, so your script works on any box that has bash somewhere in PATH — even when Apple's bash is at /bin/bash and Linux's is /usr/bin/bash. Hard-coding /bin/bash works on macOS but breaks on minimal Linux containers.
Make it executable
chmod +x script.sh
./script.shWithout chmod +x, the kernel refuses to launch. You can still run it as bash script.sh — that bypasses the shebang and uses bash explicitly.
Don't lie about the interpreter
Shebang says one thing, body uses another? Bugs. If the body uses [[ ]] (bash/zsh-only) but shebang is #!/bin/sh, POSIX sh might choke. Pick the interpreter that matches the body and stick to it.