01 · Setup & First Script¶
🎥 Video walkthrough¶
Which shell?¶
Almost every Linux distro and macOS ships with Bash. Check what you have:
echo $SHELL # /bin/bash, /bin/zsh, etc. — your login shell
bash --version # confirm bash itself is installed
macOS has used zsh as the default login shell since Catalina, but bash is
still installed and this whole site targets Bash specifically (noting POSIX
sh differences where they matter, since some systems' /bin/sh is a much
more limited shell like dash).
The terminal, briefly¶
A few things you'll use constantly:
pwd # print working directory — where am I?
ls # list files in the current directory
ls -la # list all files (incl. hidden), long format
cd some/path # change directory
cd .. # go up one level
cd - # jump back to the previous directory
clear # clear the screen
Your first script¶
Create a file called hello.sh:
The shebang line¶
#!/usr/bin/env bash is the shebang. It must be the very first line of
the file (no blank line before it) and tells the OS which interpreter to use
when the script is executed directly.
| Shebang | Meaning |
|---|---|
#!/bin/bash |
run with bash at this exact path |
#!/usr/bin/env bash |
find bash via PATH — more portable across systems |
#!/bin/sh |
run with the system's POSIX shell (may be dash, not bash) |
#!/usr/bin/env bash is the recommended default, since bash doesn't always
live at /bin/bash (some systems, like Nix-based ones, put it elsewhere).
Making it executable¶
chmod +x hello.sh # add the executable permission bit
ls -l hello.sh
# -rwxr-xr-x 1 you staff 45 Jul 18 10:00 hello.sh
# ^^^ the three x's mean owner/group/other can execute this file
Running it¶
./hello.sh # run it directly (needs +x and the shebang)
# Hello, world!
bash hello.sh # or explicitly hand it to bash — works even without +x
sh hello.sh # run under the system's sh instead
./hello.sh looks for hello.sh in the current directory (.) — plain
hello.sh won't work unless the current directory is on your PATH, which it
normally isn't (for good reason — security).
Comments¶
There is no multi-line comment syntax in Bash; every commented line needs its
own #.
A slightly bigger first script¶
#!/usr/bin/env bash
# greet.sh — greets whoever is running the script
echo "What is your name?"
read -r name # read a line of input into the variable `name`
echo "Hello, $name! Welcome to shell scripting."
read -r reads a line from standard input into a variable; -r disables
backslash escaping so backslashes in the input are kept literally — almost
always what you want.
How It Actually Works¶
When you run ./script.sh, the kernel doesn't magically know it's a shell
script. It reads the first two bytes of the file looking for a #! (the
"shebang" magic number). If it finds one, it takes the rest of that first
line — /usr/bin/env bash — as the interpreter, and re-executes the file as
interpreter path/to/script.sh via the execve() system call. Without a
shebang (or without the execute bit set via chmod +x), the kernel refuses
to run the file directly and you'd have to invoke bash script.sh yourself.
#!/usr/bin/env bash vs #!/bin/bash matters because env performs a
$PATH search for bash at run time, so the script follows whichever bash
a user has installed (useful on machines where bash lives outside
/bin), while a hardcoded #!/bin/bash always uses that exact binary.
When you type a command at an interactive prompt, the shell itself doesn't
"run" anything for builtins like cd or echo — those execute inside the
shell's own process. For an external command like ls, the shell calls
fork() to clone itself (a near-instant copy-on-write duplicate of its
memory pages), then the child calls execve() to replace its own process
image with the ls binary, and the parent shell calls wait() to block
until that child exits and reports an exit status back through $?.
Cheat sheet¶
| Command | Purpose |
|---|---|
pwd |
print current directory |
ls -la |
list all files, long format |
cd path |
change directory |
chmod +x file |
make a file executable |
./script.sh |
run a script in the current directory |
bash script.sh |
run a script with bash explicitly |
read -r var |
read a line of input into var |
🔀 See this in another language¶
Exercise¶
Write intro.sh that prints your name, today's date (use the date command),
and the current working directory (pwd), each on its own line. Make it
executable and run it with ./intro.sh.