Script foundations

Create an executable script

Write a Bash script with an interpreter line, make it executable, and run it from a predictable directory.

A shell script is a text file containing commands. When you run it, the operating system starts an interpreter and feeds it the file. The interpreter line on the first line, often called the shebang, tells the operating system which program should read it.

Write the script

Create a file named hello:

#!/usr/bin/env bash

printf '%s\n' 'hello from a script'

The first line must start with #!. I use #!/usr/bin/env bash instead of a hardcoded /bin/bash because env finds Bash wherever it lives on PATH. On macOS the system Bash in /bin is ancient, and the current one from Homebrew sits somewhere else entirely. env picks the right one on each machine.

printf '%s\n' 'text' is the predictable way to print. Unlike echo, it never reinterprets escapes or flags hidden inside the value.

Make it executable and run it

A fresh file is not executable. Give yourself execute permission, then run it:

chmod u+x hello
./hello
# hello from a script

If you skip chmod, the shell answers Permission denied. That error means the file exists but you are not allowed to execute it. The fix is the permission, not the path.

Why the ./ prefix

The ./ prefix names the file in the current directory. Without a slash, the shell searches directories in PATH, and the current directory is not on that list:

hello
# bash: hello: command not found
./hello
# hello from a script

This trips up everyone once. command not found for a file sitting right there means you forgot the ./.

Do not add the current directory to PATH globally to “fix” this. Any directory you cd into could then shadow real commands with a malicious file named ls. Run local scripts through an explicit path.

The shebang stays in charge

You can also run a script without execute permission by naming the interpreter yourself:

bash hello
# hello from a script

That works, but it ignores the shebang. If someone runs a Bash-only script with sh this way, the syntax breaks in confusing places. Making the file executable and running ./hello keeps the interpreter line in control.

Lesson completed