Linux › Module 6 › Lesson 4
Bash Scripting Basics
Write your first bash scripts with variables, if, and loops
Opening
Stop repeating yourself
If you ran the same five commands twice today, the third time belongs in a file. A bash script is plain text the shell executes in order — automation for analysts, admins, and anyone tired of retyping whoami, pwd, and date into a notes folder. This lesson is literacy, not wizardry: shebang, variables, quoting, if tests, exit codes, chmod +x, and a tiny loop pattern you can reuse safely. Unquoted $1 is not a style nit. It is how a filename with spaces — or a crafted argument — becomes many words the script never intended to see. You will practice only under $HOME/cyberlium-lab on a machine you own. No eval of user input. No destructive rm of arguments.
1. Shebang and chmod +x
Line 1 should be #!/bin/bash (the shebang). It tells the kernel which interpreter to use when you run ./script.sh. Without a shebang, some environments may still run the file with a default shell — but you should not rely on that. Be explicit. #!/usr/bin/env bash is another common form that searches PATH for bash.
Without execute permission, the kernel will not launch ./script.sh that way — chmod +x script.sh adds the execute bit for the owner (on a file you own under your home). You can always bash script.sh instead, which ignores the need for +x but still needs a readable file. Prefer chmod +x only on scripts you wrote and reviewed. Never chmod +x a mystery download "so it runs."
2. Variables, arguments, and why quotes are safety gear
NAME="analyst" stores a string. echo "User: $NAME" expands it. Quotes around the assignment keep spaces inside one value. When you expand, prefer "$NAME" so the result stays one word even if it contains spaces. Unquoted expansions undergo word splitting and globbing: a variable holding * can turn into a list of filenames in the current directory — a surprise you do not want in automation.
Positional arguments are $1, $2, and so on; $# is the count; "$@" is all arguments as separate quoted words when used correctly. A script that runs rm $1 (unquoted) is a classic accident: if $1 is My Report.txt, rm sees two arguments; if someone passes a glob or extra words, you may touch files you never named. Always "$1" unless you have a precise, documented reason not to. This course will not teach you to rm user input in the lab — quoting still matters for echo, mkdir, cat, and test.
Default values help: TARGET="${1:-$HOME/cyberlium-lab}" uses $1 if provided, otherwise a safe lab path. That pattern keeps scripts usable with zero arguments without inventing dangerous fallbacks like /.
3. if tests, [, and exit codes
Every command returns an exit status: 0 usually means success, non-zero means failure. echo $? prints the last status. Scripts should exit 0 when they did their job and a non-zero code when they cannot — so other scripts, cron wrappers, and CI can detect failure. Silent "success" on failure hides bugs until production.
if [ -d "$TARGET" ]; then … fi tests whether a path is a directory. [ is a command (test); the spaces around [ and ] are required. Quote "$TARGET" inside [ ] so a path with spaces is one operand. An unquoted empty variable can make [ ] parse as a broken test and behave surprisingly. Common tests: -f (regular file), -d (directory), -e (exists), -z (string empty), -n (string non-empty). Learn them slowly on files you own.
set -e near the top makes the script exit when a command fails (with some caveats around if and pipelines). It is not magic armor, but it beats continuing after a failed mkdir and writing into the wrong place. Combine with clear messages on stderr: echo "error..." >&2; exit 1.
4. A tiny loop without getting clever
for f in "$HOME/cyberlium-lab"/*.txt; do echo "$f"; done is a readable pattern for iterating files you already created. Quote "$f" inside the loop. Avoid for loops that expand untrusted globs over system directories. Keep loops inside your lab tree. Clever one-liners that parse ls are fragile; prefer globs or find you understand, and never pipe find into a destructive command for "practice."
5. Wrong vs right: unquoted $1
Worked failure mode — "it worked on my one-word filename":
Wrong
A helper script does cat $1 > report.txt. A teammate runs ./helper.sh "auth log copy.txt". The shell splits the name. cat looks for auth, then log, then copy.txt. Wrong files, wrong error, or worse if the next line were a destructive command. A hostile argument with * would expand to whatever sits in the current directory. "It worked on notes.txt" is not a security review.
Right
Use "$1", quote variables in tests, and treat arguments as data — not as raw shell code. Start scripts with a shebang, chmod +x only on files you wrote under $HOME/cyberlium-lab, exit with a status that matches success or failure, and never eval "$1".
6. Practical: a tiny quoted script you own
Write this under $HOME/cyberlium-lab only on YOUR VM or WSL. Do not cat or rm paths from strangers. No destructive commands in the script. If ./hello.sh says Permission denied, check chmod +x before inventing SUID "fixes."
Command guide
hello.sh — shebang, quotes, if, exit (your machine)
Command — copy this
mkdir -p "$HOME/cyberlium-lab" cd "$HOME/cyberlium-lab"
Command — copy this
cat > hello.sh << 'EOF'
#!/bin/bash
set -e
TARGET="${1:-$HOME/cyberlium-lab}"
echo "Hello from Cyberlium"
echo "User: $(whoami)"
echo "PWD: $(pwd)"
if [ -d "$TARGET" ]; then
echo "Directory exists: $TARGET"
# Tiny safe loop over .txt files if any exist
shopt -s nullglob
for f in "$TARGET"/*.txt; do
echo "Found text file: $f"
done
exit 0
else
echo "Not a directory: $TARGET" >&2
exit 1
fi
EOFCommand — copy this
chmod +x hello.sh ./hello.sh "$HOME/cyberlium-lab" echo "exit code was $?"
Show why quotes matter (safe demo — echo only)
Command — copy this
demo='two words' echo unquoted: $demo echo quoted: "$demo"
DO NOT: rm $1 DO NOT: eval "$1" DO NOT: chmod +x scripts you did not write and do not understand DO NOT: set a default TARGET to / or another system path
Mission: shebang, +x, and quotes
Create $HOME/cyberlium-lab/hello.sh with a shebang, chmod +x, and run ./hello.sh. Confirm it prints whoami and uses "$TARGET" or "$1" in a test. Optional: add a for loop that only echoes *.txt names under your lab folder. Write one sentence: "Unquoted $1 is dangerous because ___."
Stuck? Ask Cyberlium AI Mentor
If shebang, chmod +x, or quoting feels fuzzy, ask Cyberlium AI Mentor for a hint — not an eval-based "clever" parser. Try: "Hint only: why does ./script.sh fail with Permission denied?" Or: "Hint only: what goes wrong if I cat $1 without quotes?" Practice only on your own lab files.
You can write a shebang script, set the execute bit, branch on a test, quote expansions so arguments stay data, and exit with a status callers can trust. Next — Lab — Mini Automation Script — you will put whoami, pwd, and date into $HOME/cyberlium-lab/sysinfo.sh and run it.
Knowledge Check
APPLY: ./hello.sh says Permission denied even though the file exists and starts with #!/bin/bash. Most likely missing piece?
Multiple choice
Knowledge Check
APPLY: Why is cat $1 (unquoted) dangerous compared with cat "$1"?
Multiple choice
Knowledge Check
APPLY: True or False: A script should exit 0 on success and non-zero when it cannot do its job, so callers can detect failure.
True or False