Bash Syntax

Every Bash script starts with a shebang line and needs the right permissions before you can run it directly, two small details that trip up almost everyone at first.

The Shebang Line

The first line of a Bash script, #!/bin/bash, is called the shebang (or hashbang). It tells the operating system which interpreter should execute the rest of the file, so the script can be run directly instead of always being passed to bash explicitly.

Running a Script Through the Interpreter

You can always run a script by passing its path to bash directly. This works even without execute permission, because you are not asking the operating system to execute the file itself -- you are asking bash to read and interpret its contents.

Running with bash

$ cat hello.sh
#!/bin/bash
echo "Hello, $(whoami)!"
echo "Today is $(date +%A)"
$ bash hello.sh
Hello, maria!
Today is Thursday

Why ./hello.sh Fails at First

To execute the file directly as ./hello.sh, the filesystem needs execute permission set on it, and Bash needs the ./ prefix because the current directory is deliberately left out of PATH for security reasons -- otherwise a malicious file named ls sitting in a folder you cd into could hijack a common command.

Permission Denied Before chmod

$ ./hello.sh
bash: ./hello.sh: Permission denied
$ ls -l hello.sh
-rw-r--r-- 1 maria maria 58 Jul 16 09:00 hello.sh

Making the Script Executable with chmod +x

chmod +x adds execute permission for the owner, group, and others in one step. The x in the permission string (rwxr-xr-x) is what allows a file to be run as a program instead of only opened as text.

After chmod +x

$ chmod +x hello.sh
$ ls -l hello.sh
-rwxr-xr-x 1 maria maria 58 Jul 16 09:00 hello.sh
$ ./hello.sh
Hello, maria!
Today is Thursday
  • chmod +x file - add execute permission for everyone
  • chmod u+x file - add execute permission for the owner only
  • chmod 755 file - set rwxr-xr-x explicitly using numeric mode
  • chmod -x file - remove execute permission
Note: Keep the shebang as the very first line with nothing above it, not even a blank line or a comment -- even a single leading space stops the kernel from recognizing it.
Note: #!/bin/bash and #!/usr/bin/env bash both work, but env bash finds bash wherever it lives on the user's PATH, which makes scripts more portable across systems where bash is not installed at /bin/bash.

Exercise: Bash Syntax

What is the purpose of the `#!/bin/bash` line at the very top of a script?