for Loops: Once per Item
backup.sh should now make one archive per folder, so a broken photo folder does not spoil the notes backup. Writing the tar line three times would work until someone adds a fourth folder. A for loop runs the same body once for each item, however many there are.
The rule
for name in list; do body; done: the body runs once per word.
for dir in "${dirs[@]}"; do
name="${dir##*/}"
tar -czf "$dest/${name// /_}-$stamp.tar.gz" "$dir"
echo "Packed $dir"
doneOn each pass, dir holds the next item, then the body runs. The list can come from many places:
for dir in "${dirs[@]}"; do ... # an array
for dir in "$@"; do ... # the script's arguments
for dir; do ... # short for: in "$@"
for f in "$dest"/*.tar.gz; do ... # files matching a pattern
for n in {1..5}; do ... # a brace range: 1 2 3 4 5
for (( i = 0; i < 3; i++ )); do ... # a counter: 0 1 2The file pattern form is the safe way to loop over files: each matching name arrives whole, spaces and all. Avoid for f in $(ls): the output of ls is split on spaces, so My Notes.txt becomes two items. One more surprise: if a pattern matches nothing, the loop runs once with the pattern itself, such as the literal text *.log. Guard with [[ -e "$f" ]] || continue.
The shortcut
Expand the list first, then count the words. Before reading the body, write out exactly what the list becomes after quoting and expansion. The number of words is the number of passes.
Expand the list
Three words:
a,b c(the quotes keep it together) andd.
Drills
Answer fast — trust the rule.
How many times does the body run in for x in a "b c" d; do echo "$x"; done?
How many passes does for n in {1..4} make?
Which values does i take in for (( i = 0; i < 3; i++ ))?
In a folder with no .log files, what does for f in *.log; do echo "[$f]"; done print?
Why is for f in $(ls) a poor way to loop over files?
Remember
for name in list; do body; done: once per word.- Expand the list first, then count the words.
- Loop over files with a pattern, never
$(ls); an unmatched pattern stays literal.
