You want to repeat the same small task for several values. A loop describes that repetition once. Before running it, follow each assigned value and separate the loop's output from any commands that run afterward.
A variable stores a value under a name. Expansion substitutes that value into a command. A loop repeats a body of commands, while a condition decides whether a command block runs. Bash also returns an exit status: zero conventionally means success, and nonzero describes another outcome. That number is separate from printed text.
Before you begin
- Recommended first
- Install Ubuntu LTS and open a terminal, Where practice is allowed, SSH, keys, and a non-default port
- Estimated time
- 25 min reading, 25 min activity. Setup and optional practice may take longer.
- Where you work
- Use Bash in your owned Ubuntu practice environment as an ordinary user. The supplied text files use UTF-8, a text encoding; where shown, LC_ALL=C requests consistent text ordering. Work only under your own new ~/yanosec-lab directory, never a host share or personal/system file. Refuse an existing exercise destination rather than overwriting it. No account, paid platform, or remote target is required. Optional extensions take about 10–15 minutes and are not part of the time above. A virtual machine is optional. You can also finish the reasoning from the printed evidence.
- Without a lab
- The page supplies the files, source and text records needed for the activity. Without a shell, follow the numbered steps on paper, label each result as predicted, and use the separate evidence supplied by the question. Running commands can wait until your lab is available. Reading works without JavaScript. Answer checking needs JavaScript and a secure context, such as HTTPS; saving a correct result also needs usable browser storage. Missing tools, managed or mobile hosts, or a deferred guest setup never require buying a service. Keep owned lab files for review; do not use broad deletion.
After this lesson you can:
- Predict the argument produced by a quoted variable expansion.
- Trace a three-item loop and a separate condition.
- Count body executions in an independent fixed iteration list.
01Example
The variable value contains a space. Assigning it uses no spaces around =. Quoting its later expansion keeps the entire value in one argument for printf. Read the predicted output separately from the two commands.
Commands:
note_label='red blue'
printf '%s\n' "$note_label"
Predicted stdout, one line:
red blue
Without quotes, expansion may split words or expand filename patterns.
Quoting preserves argument boundaries; it does not authorize actions.02Read one construct at a time
In note_label='red blue', the assignment has no spaces around =. The straight quotes keep the two words together as its value. Later, "$note_label" expands that value as one argument. Quoting an expansion preserves its argument boundary instead of allowing word splitting or filename expansion.
The loop for tone in amber violet silver; do ...; done assigns each listed value to tone and runs the body once per value. do starts the body and done ends it. A semicolon or newline separates shell commands. "$tone" passes the current value to printf as one argument.
The command if [ -n 'practice' ]; then ...; fi tests whether a string is nonempty. The [ command receives -n and the string as arguments, then a closing ] argument; those spaces matter. A successful test gives status zero, so the commands after then run. fi ends this condition.
A command after done is outside the loop. Its printed line does not create another iteration. Make one trace row per assignment, then a separate row for the later condition. Count body executions and output lines separately.
Use task-specific variable names. HOME and PATH already affect home-directory expansion and command lookup, so do not replace them for an exercise. The supplied script only prints text. Review source before using any later script that can change files or contact another system.
Quoted variable expansion preserves red blue as one argument, then printf produces one predicted output line.Model. A teaching model drawn by hand. It shows the idea, not real tool output.
Read the full explanation below.
Playback is optional. Step through at your own pace.
Instruction being read
note_label='red blue'Saved variable value
note_label = red blueassigned
printf value arguments
not yet passedabsent
Predicted stdout
not yet printedunobserved
No spaces surround =; the assigned text includes the space in red blue.
Follow the explanation
- No spaces surround =; the assigned text includes the space in red blue.
- Quoted expansion passes one argument whose contents are red blue.
- The format prints that one value argument as one line.
Read every state and value
1. No spaces surround =; the assigned text includes the space in red blue.
- Current command
- note_label='red blue'
- Data in each location
- Pane: Saved variable value; Text: note_label = red blue; Status: assigned · Pane: printf value arguments; Text: not yet passed; Status: absent · Pane: Predicted stdout; Text: not yet printed; Status: unobserved
- Links
- From: note_label='red blue'; To: Saved variable value; Label: assign whole value
2. Quoted expansion passes one argument whose contents are red blue.
- Current command
- printf '%s\n' "$note_label"
- Data in each location
- Pane: Saved variable value; Text: note_label = red blue; Status: assigned · Pane: printf value arguments; Text: one value argument: red blue; Status: predicted · Pane: Predicted stdout; Text: not yet printed; Status: unobserved
- Links
- From: Saved variable value; To: printf value arguments; Label: quoted expansion: one argument
3. The format prints that one value argument as one line.
- Current command
- printf '%s\n' "$note_label"
- Data in each location
- Pane: Saved variable value; Text: note_label = red blue; Status: assigned · Pane: printf value arguments; Text: one value argument: red blue; Status: predicted · Pane: Predicted stdout; Text: red blue ; Status: predicted
- Links
- From: printf value arguments; To: Predicted stdout; Label: one formatted line
03Try tracing then running
The complete script source supplies the activity evidence. It uses three tone values and then a separate conditional command. The accompanying transcript retains output recorded earlier with Bash 5.2.21; compare your prediction with that record without treating it as a new run.
On paper, mark each assignment, the line printed by the body, and the later nonempty test. If running it, use Bash explicitly after reading all source. UTF-8 describes the text encoding; LF means the Linux-style line ending. These details help avoid confusing a text-format problem with a permission problem.
#!/bin/bash
# Original harmless trace.
for tone in amber violet silver; do
printf '%s\n' "$tone"
done
if [ -n 'practice' ]; then
printf '%s\n' 'nonempty'
fi
Trace the loop body separately from later commands
Read trace-loop.sh first. Make a row for each assigned tone value, then
a separate row for the condition after done. The record below retains
earlier output from Bash 5.2.21. Comparing your prediction with that
record does not mean you have executed the script yourself.
trace-loop.sh stdout observed with Bash 5.2.21:
amber
violet
silver
nonempty
Three loop iterations; the conditional line is outside the loop.
Separate question loop: for tone in red blue green white; do ...; done
Assume no nested loop, break, return or exit. Count body runs only.
- Read the complete trace-loop.sh source. Make a paper row for each tone assignment, its printed value and the conditional test after the loop. Expected: three body runs.
- Predict the separate conditional line. Expected: nonempty after amber, violet and silver because the test's string is nonempty. That fourth output line is not a fourth loop iteration.
- If doing live work, save the exact source as a UTF-8 file with LF newlines under your owned lab and run bash with its quoted actual path, such as bash ~/Downloads/trace-loop.sh. The command interprets the reviewed source; no execute-bit change is needed.
- Compare actual stdout with the four predicted lines. If you see a parsing issue, inspect quotes, newlines and which interpreter ran; do not add permissions or sudo to fix syntax.
- Keep the source and trace note. No background job, file write or remote action occurs, so execution needs no operational cleanup. Paper-only work is marked execution deferred.
04Optional challenge
Allow about ten extra minutes. Move the conditional inside the loop on paper. Predict each printed line in order and compare body count with output count. Explain which boundary changed; you do not need to edit or run another script.
05Fresh cases for the checks
Use these fictional cases for the checks below. They have different inputs from the worked examples. Read them here or make notes; no installation or external service is needed.
Bash card A: a new quoted expansionOwned fixture. An original file made for this course. Follow the activity's instructions in your own lab.
parcel_label='copper grey'
printf '%s\n' "$parcel_label"
Predict the value arguments after the format string, not the format string itself.
Source-reading case only; no execution is recorded.
Bash card B: a condition inside a loopOwned fixture. An original file made for this course. Follow the activity's instructions in your own lab.
for badge in "" teal "" coral; do
if [ -n "$badge" ]; then
printf '%s\n' "$badge"
fi
done
printf '%s\n' 'complete'
Each quoted empty string is a listed loop value. Predict stdout; no run is recorded.
Bash card C: independent body-count sourceOwned fixture. An original file made for this course. Follow the activity's instructions in your own lab.
for stop_name in "north wing" central "south wing" annex courtyard; do
printf '%s\n' "$stop_name"
done
printf '%s\n' 'route-end'
No nested loop, early exit or other control flow is present.
Bash card D: diagnose a changed expansionOwned fixture. An original file made for this course. Follow the activity's instructions in your own lab.
room_label='east hall'
Original command: printf '%s\n' "$room_label"
Changed command: printf '%s\n' $room_label
Assume ordinary Bash whitespace word splitting. The value contains no filename-pattern characters.
For this printf format, each resulting value argument is printed on its own line.
Only the quotes around the expansion are removed. Predict value arguments and stdout.
Bash card E: a separate changed conditionOwned fixture. An original file made for this course. Follow the activity's instructions in your own lab.
stamp=''
if [ -n "$stamp" ]; then
printf '%s\n' 'inside'
fi
printf '%s\n' 'closed'
Compared with a nonempty stamp, this card changes only its value to the empty string.
06Explain arguments, iterations and output
Optional self-check: explain why a multiword variable value can be one argument, why a loop visit need not print, and why a command after done does not add a loop iteration.
Review your explanation: connect double quotes to preserved argument boundaries; evaluate -n using the current string; mark do/done and then/fi boundaries; and distinguish value arguments, body runs and output lines. Keep predictions separate from any actual run. This explanation is self-reviewed.
07Common mistakes
If a spaced assignment is treated as a command, inspect syntax: note_label='red blue' has no spaces around =. Keep straight quotes and the task-specific variable name.
If a string containing spaces becomes several printed items, inspect whether expansion was quoted. Do not assume a variable's display determines its argument count.
If you count every output line as an iteration, locate do/done and inspect commands outside the body. The independent question loop states there is no early exit or nesting.
References
- Ubuntu 24.04 packaged manual: bash(1)
Shell grammar, quoting, builtins, redirection and job control; use only the sections introduced in this lesson. Use the named command and option sections. This manual describes Ubuntu 24.04 packages; your installed version can differ. The lesson supplies the facts needed for its activity.
- Ubuntu 24.04 packaged manual: printf(1)
Use the named command and option sections. This manual describes Ubuntu 24.04 packages; your installed version can differ. The lesson supplies the facts needed for its activity.