Skip to content
← System engineer foundations

Learning bite

Bash arguments and quoting

Preserve argument boundaries and make a script interface explicit.

Documentation reviewed2026-10-01 · 3 min read
On this page

A shell runs commands and connects their results

Bash reads a command, expands its arguments, finds the executable or built-in command, and runs it. A script stores those steps in a file. We will inspect paths, not change services. Run this module in Bash inside the Ubuntu machine; macOS's usual interactive Zsh is a different interpreter.

Create a new directory with mkdir -p ~/foundations-shell, then cd ~/foundations-shell. Use it only for this module's practice files. A variable assignment has no spaces around =:

bash
study_name='file with spaces.txt'
printf 'sample\n' > "$study_name"
printf '<%s>\n' "$study_name"
printf '<%s>\n' $study_name

Expected output from the quoted form is one line, <file with spaces.txt>. The unquoted form produces three lines. Bash split the value into words before printf saw it; unquoted expansions may also expand wildcard patterns into filenames. Single quotes preserve literal characters. Double quotes allow variable expansion while preserving one argument. The value is data, so do not put it into a command string and run eval.

Give a script a clear interface

Save the following as inspect-path.sh in this directory. The quoted EOF prevents your current shell expanding variables while writing the script:

bash
cat > inspect-path.sh <<'EOF'
#!/usr/bin/env bash
if [[ $# -ne 1 ]]; then
  printf 'Usage: %s PATH\n' "$0" >&2
  exit 2
fi
study_target=$1
if [[ ! -e "$study_target" ]]; then
  printf 'Path does not exist: %s\n' "$study_target" >&2
  exit 1
fi
printf 'Inspecting: %s\n' "$study_target"
ls -ld -- "$study_target"
EOF
bash inspect-path.sh "$study_name"
bash inspect-path.sh "$HOME"

$# is the argument count, $0 the script name, and $1 its first argument. An if runs the commands after then when its test returns status 0. [[ ... ]] is Bash's conditional syntax; -ne means numerically unequal, -e tests whether a path resolves to an existing object, and ! reverses the test. fi closes the conditional. We check the count before reading $1.

>&2 directs a message to the error stream. exit 2 ends this script with its chosen usage-error status; exit 1 reports a missing target. Otherwise the final ls status becomes the script status. -- ends options for ls, so a name beginning with - is treated as a path. A dangling symbolic link fails -e, and an existing file may disappear before ls; this check is not a lock.

You can also make the script executable with chmod u+x inspect-path.sh and run ./inspect-path.sh .. ./ supplies a path instead of asking Bash to find the program in PATH. The shebang selects Bash for direct execution; sh inspect-path.sh explicitly chooses another shell and may reject [[ ... ]].

Repeat a check without losing argument boundaries

A loop assigns each listed value to a variable and runs its body once per value:

bash
for study_path in . 'file with spaces.txt' './missing-study-path'; do
  if bash inspect-path.sh "$study_path"; then
    printf 'Inspection succeeded\n'
  else
    printf 'Inspection failed\n' >&2
  fi
done

Expect two successes and one missing-path failure. The spaces in the second path remain part of one argument. A function gives a group of commands a name:

bash
inspect_many() {
  local study_path
  for study_path in "$@"; do
    bash inspect-path.sh "$study_path"
  done
}
inspect_many . 'file with spaces.txt'

local keeps the loop variable within the function. "$@" preserves each supplied argument separately; "$*" would combine them into one string. This simple function returns the last command's result, so it is not yet a complete all-inputs success check.

Try no arguments and two arguments, predicting which if runs. Both return usage status 2 without inspecting a path. Keep the script and spaced filename for the testing bite. Next, connect commands using streams and pipes.

Sources

Primary references: Bash quoting↗; Bash conditional expressions↗.

Your notes and evidence

Record observations, questions, or links to your work. Keep credentials out of your notes.

Loading saved progress…

Back up or restore this path

Progress and notes stay in this browser. A backup contains only this learning path.