Study guide
7.2 Looping Constructs for Files and Input
Red Hat Certified System Administrator RHCSA
Track your progress as you read
Finished sections get a check mark.
1 Introduction & Exam Overview
1.1 Current Exam Facts 1.2 Lab Setup & Performance-Based Study Strategy
2 Essential Tools: Shell, Redirection & Text Analysis
2.1 Shell Prompt and Command Syntax 2.2 Input-Output Redirection and Pipes 2.3 grep and Regular Expressions for Text Analysis
3 Essential Tools: Remote Access, Users & Text Editing
3.1 Access Remote Systems Using SSH 3.2 Log In and Switch Users in Multiuser Targets 3.3 Create and Edit Text Files
4 Essential Tools: Files, Links & Archives
4.1 Create, Delete, Copy, and Move Files and Directories 4.2 Hard and Soft Links 4.3 Archive and Compress with tar, gzip, and bzip2
5 Essential Tools: Permissions & System Documentation
5.1 List, Set, and Change Standard ugo/rwx Permissions 5.2 System Documentation: man, info, and /usr/share/doc
6 Manage Software: RPM and Flatpak
6.1 Configure Access to RPM Repositories 6.2 Install and Remove RPM Software Packages 6.3 Configure Access to Flatpak Repositories 6.4 Install and Remove Flatpak Software Packages
7 Create Simple Shell Scripts
7.1 Conditional Execution: if, test, and [] 7.2 Looping Constructs for Files and Input 7.3 Process Script Inputs ($1, $2, and Beyond) 7.4 Process Shell Command Output in Scripts
8 Operate Running Systems: Boot and Recovery
8.1 Boot, Reboot, and Shut Down a System Normally 8.2 Boot Systems into Different Targets Manually 8.3 Interrupt the Boot Process to Gain Access
9 Operate Running Systems: Processes and Tuning
9.1 Identify and Kill CPU/Memory Intensive Processes 9.2 Adjust Process Scheduling 9.3 Manage Tuning Profiles
10 Operate Running Systems: Logs, Services & File Transfer
10.1 Locate and Interpret System Log Files and Journals 10.2 Preserve System Journals 10.3 Start, Stop, and Check Status of Network Services 10.4 Securely Transfer Files Between Systems
11 Configure Local Storage: Partitions and LVM
11.1 List, Create, and Delete Partitions on GPT Disks 11.2 Create and Remove Physical Volumes 11.3 Assign Physical Volumes to Volume Groups 11.4 Create and Delete Logical Volumes
12 Configure Local Storage: Mounting and Expansion
12.1 Mount File Systems at Boot by UUID or Label 12.2 Add Partitions, Logical Volumes, and Swap Non-Destructively
13 Create and Configure File Systems: Local FS and Permissions
13.1 Create, Mount, and Use VFAT, ext4, and XFS File Systems 13.2 Extend Existing Logical Volumes 13.3 Diagnose and Correct File Permission Problems
14 Create and Configure File Systems: NFS and autofs
14.1 Mount and Unmount Network File Systems Using NFS 14.2 Configure autofs
15 Deploy and Maintain: Scheduling, Services & Targets
15.1 Schedule Tasks with at, cron, and systemd Timers 15.2 Start, Stop, and Enable Services at Boot 15.3 Configure Systems to Boot into a Specific Target
16 Deploy and Maintain: Time, Software Updates & Bootloader
16.1 Configure Time Service Clients 16.2 Install and Update Software from CDN, Remote Repos, and Local Files 16.3 Modify the System Bootloader
17 Manage Basic Networking
17.1 Configure IPv4 and IPv6 Addresses 17.2 Configure Hostname Resolution 17.3 Configure Network Services to Start Automatically at Boot 17.4 Restrict Network Access Using firewalld and firewall-cmd
18 Manage Users and Groups
18.1 Create, Delete, and Modify Local User Accounts 18.2 Change Passwords and Adjust Password Aging 18.3 Create, Delete, and Modify Local Groups and Memberships 18.4 Configure Privileged Access
19 Manage Security: Firewall, umask & SSH Keys
19.1 Configure Firewall Settings with firewall-cmd and firewalld 19.2 Manage Default File Permissions 19.3 Configure Key-Based Authentication for SSH
20 Manage Security: SELinux Modes and Contexts
20.1 Set Enforcing and Permissive Modes for SELinux 20.2 List and Identify SELinux File and Process Contexts 20.3 Restore Default File Contexts
21 Manage Security: SELinux Ports and Booleans
21.1 Manage SELinux Port Labels 21.2 Use Boolean Settings to Modify SELinux Settings
7.2 Looping Constructs for Files and Input
Key Takeaways Explain This Topic AI
for loops iterate word lists, globs, ranges, or command substitution results—ideal for acting on many files or names in EX200 scripts.
while loops repeat as long as a condition or read pipeline succeeds; they are the right tool for line-oriented input and counters.
Combine loops with if/test from Section 7.1 so each iteration can skip, log, or fail cleanly without aborting the whole system.
Quote variables in loops; for f in $list without quotes breaks on spaces—prefer for f in "$dir"/* patterns carefully or while read -r .
Keep exam scripts short: loop, check, act, exit—avoid complex nested control flow that is hard to debug under time pressure.
Last updated: August 2026
7.2 Looping Constructs for Files and Input
Quick Answer: Use for to walk a list (files, names, numbers) and while to repeat while a condition holds or while read returns lines. Inside the loop body, use if / test to decide what to do per item. End for / while with done . Keep scripts executable with #!/bin/bash and chmod +x .
Where loops fit on EX200
Conditional execution decides once . Looping constructs decide for each of many items—exactly what admins automate:
- Apply a fix to every .conf under a directory
- Create several users or directories from a list
- Parse each line of a report or stdin
- Retry or poll until a condition clears (with care on timed exams)
Official wording emphasizes simple scripts. Graders want correct end state and a working script, not clever golf.
- for loops: the workhorse
- List form #!/bin/bash
- for name in alice bob carol; do
- echo "processing $name"
- done
Words after in are the iteration values. do … done is the body.
- Glob form (files) #!/bin/bash
- for f in /etc/ssh/*.conf; do
- if [ -f "$f" ]; then
- echo "file: $f"
- fi
- done
When a glob matches nothing, bash’s default behavior may leave the pattern as a literal string (depending on nullglob ). Guard with [ -f "$f" ] or [ -e "$f" ] so you do not act on a fake path named *.conf .
- Safer pattern for “all regular files here”: #!/bin/bash
- DIR="/var/tmp/examdata"
- for f in "$DIR"/*; do
- [ -f "$f" ] || continue
- echo "regular file: $f"
- done
continue skips to the next iteration; break exits the loop early.
- C-style numeric for (bash) for ((i=1; i<=5; i++)); do
- echo "n=$i"
- done
Useful for counters and numbered files ( file1 … file5 ). Requires #!/bin/bash , not pure POSIX sh .
- Brace expansion for n in {1..3}; do
- mkdir -p /tmp/exam/dir$n
- done
Brace expansion happens before the loop runs. Good for small fixed ranges in lab scripts.
- Command substitution as the list for user in $(cut -d: -f1 /etc/passwd); do
- echo "$user"
- done
Warning: word-splitting applies. Usernames without spaces are fine; arbitrary filenames with spaces are not safe this way. For filenames, prefer globs or while read (below).
- while loops: conditions and line input
- Condition form #!/bin/bash
- count=1
- while [ "$count" -le 3 ]; do
- echo "count=$count"
- count=$((count + 1))
- done
The loop continues while the condition command exits 0 . Arithmetic uses $(( ... )) in bash.
- until (awareness) until [ -f /var/lock/ready ]; do
- sleep 1
- done
until runs until the condition succeeds . On EX200 you rarely need long waits—do not sleep in tight infinite loops during a timed exam unless the task demands waiting.
- Reading lines: the admin classic #!/bin/bash
- # Process each non-empty line of a file
- while IFS= read -r line; do
- [ -z "$line" ] && continue
- echo "LINE: $line"
- done < /root/names.txt
- Piece Role
- IFS= Do not trim leading/trailing whitespace oddly; empty IFS preserves line content better for many cases
- read -r Do not treat backslashes as escapes
- done < file Redirect file into the loop’s stdin
- From a pipeline: cut -d: -f1 /etc/passwd | while IFS= read -r user; do
- echo "$user"
- done
Exam note: a while after a pipe often runs in a subshell in bash, so variable assignments inside may not persist outside. For EX200 scripts that only print or call commands per line, that is usually fine. If you must accumulate a counter outside, prefer done < file redirection over a pipe when possible.
- Reading space-separated fields while read -r col1 col2 rest; do
- echo "first=$col1 second=$col2 rest=$rest"
- done < /tmp/data.txt
read splits on IFS (default whitespace).
- Nesting with if and exit status
- Loops without conditionals are rare in real tasks: #!/bin/bash
- # Ensure every listed path is a directory; create if missing; fail on file collision
- for path in /opt/app/data /opt/app/logs /opt/app/tmp; do
- if [ -d "$path" ]; then
- echo "exists dir: $path"
- elif [ -e "$path" ]; then
- echo "ERROR: $path exists and is not a directory" >&2
- exit 1
- else
- mkdir -p "$path" || exit 1
- echo "created: $path"
- fi
- done
- exit 0
Failing fast with exit 1 inside a loop is appropriate when continuing would leave a half-configured system.
- Practical exam scripts
- Bulk ownership on files matching a pattern #!/bin/bash
- # chown-web.sh — set owner for web content files
- WEBROOT="/var/www/html"
- OWNER="apache:apache"
- if [ ! -d "$WEBROOT" ]; then
- echo "Missing $WEBROOT" >&2
- exit 1
- fi
- for f in "$WEBROOT"/*; do
- [ -f "$f" ] || continue
- chown "$OWNER" "$f" || exit 1
- done
- Process arguments in a loop (preview of §7.3) #!/bin/bash
- if [ $# -eq 0 ]; then
- echo "Usage: $0 file..." >&2
- exit 2
- fi
- for f in "$@"; do
- if [ -f "$f" ]; then
- wc -l < "$f"
- else
- echo "skip missing: $f" >&2
- fi
- done
"$@" preserves each argument as its own word—critical when paths have spaces.
- Inventory script writing results #!/bin/bash
- OUT=/root/bin-inventory.txt
- : > "$OUT" # truncate/create
- for f in /usr/local/bin/*; do
- [ -x "$f" ] || continue
- ls -l "$f" >> "$OUT"
- done
: > file is a common truncate idiom; >> appends per iteration.
- Simple retry loop (use sparingly) #!/bin/bash
- tries=0
- while [ "$tries" -lt 5 ]; do
- if ping -c1 -W1 192.0.2.10 &>/dev/null; then
- echo "reachable"
- exit 0
- fi
- tries=$((tries + 1))
- sleep 1
- done
- echo "unreachable" >&2
- exit 1
Only when the task implies waiting. Blind infinite while true without break is an exam time sink.
Loop control keywords
- Keyword Effect
- continue Skip rest of body; next iteration
- break Leave the loop immediately
- exit N Leave the entire script with status N
- return Leave a function (when you use functions) for f in /etc/*; do
- [ -r "$f" ] || continue
- grep -q ExamMarker "$f" && break
- done
- Infinite loop pitfalls while true; do
...
done
Always ensure a break or exit path. On the exam, an infinite loop freezes your terminal session until Ctrl-C —know how to interrupt ( Ctrl-C ) if you make this mistake in testing.
Performance and simplicity
EX200 does not grade micro-optimization. Prefer clarity:
- One loop, obvious body
- Explicit [ -f ] guards
- Errors on stderr
- Non-zero exit when the task’s success criteria fail
Avoid deep nesting ( for inside for inside while ) unless the task forces multi-level structure.
- Combining with shebang discipline
- Every loop script still needs: #!/bin/bash
- # ... loops ... chmod +x /path/to/script.sh
- bash -n /path/to/script.sh
- ./path/to/script.sh
Syntax-check with bash -n after writing loops—missing done is a frequent typo.
Common traps
for f in $(ls dir) — breaks on spaces/newlines; use globs or find -print0 patterns carefully; for EX200, simple globs + [ -f ] are enough.
Forgetting done — parse error.
Unquoted $@ / unquoted globs mishandled — wrong word splits.
Assuming pipeline while variables persist — subshell scoping.
No guard when glob matches nothing — acts on literal * .
Using exit when you meant break — aborts whole script mid-batch.
Sleeping forever waiting for a condition that never arrives.
Section checkpoint
You should write for loops over lists and file globs, while loops with numeric conditions and read -r line processing, combine them with if / test , use continue / break / exit appropriately, protect paths with quotes and existence checks, and leave short executable scripts that process many files or input lines correctly on RHEL 10.