Your first script
A shell script is just a text file listing commands to run in order, the same commands you'd type interactively.
The shebang
Every script starts with a shebang line telling the kernel which interpreter to run it with:
#!/usr/bin/env bash
echo "Hello, $(whoami)"
#!/usr/bin/env bash finds bash on your PATH rather than hardcoding /bin/bash, more
portable across systems where bash lives somewhere else.
Making it executable
chmod +x hello.sh
./hello.sh
Hello, user
chmod +x sets the executable permission bit (see
File permissions explained for the full model). Without
it, the kernel refuses to run the file directly:
./hello2.sh
bash: ./hello2.sh: Permission denied
That failure is exit status 126, specifically "found the file, couldn't execute it," not to be
confused with 127 ("command not found") a moment below. You can still run an unexecutable
script by handing it to the interpreter directly: bash hello2.sh works with no chmod at all,
since you're not asking the kernel to execute the file, just asking bash to read and run it.
Why the ./ is required
cd /tmp
hello.sh
bash: hello.sh: command not found
Without a path, bash searches only the directories listed in $PATH, and your current directory
usually isn't one of them, deliberately: if it were, a malicious script dropped into any
directory you cd into could shadow a real command by sharing its name. ./hello.sh sidesteps
the search entirely by naming the file's exact location, so this isn't a bug to work around,
it's the safe default working as intended.
Arguments
#!/usr/bin/env bash
echo "Script name: $0"
echo "First argument: $1"
echo "All arguments: $@"
echo "Argument count: $#"
./greet.sh alice bob
Script name: ./greet.sh
First argument: alice
All arguments: alice bob
Argument count: 2
$0 is the script's own invocation path, $1, $2, and so on are positional arguments, $@
expands to all of them, and $# counts them. The next lesson covers why $@ almost always
needs to be written as "$@" (quoted) once arguments might contain spaces.
Exercises
-
Write a script that prints today's date and the current working directory, then make it executable and run it with
./.Answer
#!/usr/bin/env bash echo "Today: $(date +%F)" echo "Directory: $(pwd)"Save as
whereami.sh, thenchmod +x whereami.sh && ./whereami.sh. -
Without running
chmod +x, find two different ways to execute a script.Answer
Run it via the interpreter directly (
bash script.shorsh script.sh), orchmod +xit first and then invoke it with./script.sh. Without either the execute bit or an explicit interpreter, the kernel refuses to run the file and reports "Permission denied" (exit126). -
Write a script that prints an error and exits with status
1if it's called with no arguments.Answer
#!/usr/bin/env bash if [ $# -eq 0 ]; then echo "Usage: $0 <name>" >&2 exit 1 fi echo "Hello, $1"$#is the argument count; printing the usage message to stderr (>&2) rather than stdout is the convention for error output, covered further in Exit codes and error handling.
What's next
The next lesson covers the single biggest source of bash bugs: variables and quoting.