File Reading
Reading files is one of the most common operations in shell scripting. Whether you're processing logs, parsing configuration files, or transforming data, Bash provides multiple powerful methods for reading file content. In this lesson, you'll master techniques from simple reads to complex field parsing!
Basic File Reading Methods
Bash offers several ways to read file content. The right choice depends on whether you need the entire file, line-by-line processing, or specific portions.
Click Run to execute your code
| Method | Use Case | Example |
|---|---|---|
cat file |
Read entire file at once | content=$(cat file.txt) |
while read |
Process line by line | while read line; do ... done < file |
mapfile |
Read into array | mapfile -t arr < file |
< file |
Input redirection | command < file.txt |
while IFS= read -r line; do
echo "$line"
done < file.txt
IFS=- Preserves leading/trailing whitespace-r- Prevents backslash interpretation
Reading Parts of Files
Often you don't need the entire file. Use head, tail, and sed to extract specific portions efficiently.
Click Run to execute your code
| Command | Description | Example |
|---|---|---|
head -n N |
First N lines | head -n 10 file.txt |
tail -n N |
Last N lines | tail -n 10 file.txt |
tail -n +N |
From line N to end | tail -n +5 file.txt |
tail -f |
Follow (watch for new content) | tail -f /var/log/syslog |
sed -n 'N,Mp' |
Lines N through M | sed -n '5,10p' file.txt |
tail -f for real-time log monitoring. Combine with grep to filter: tail -f /var/log/syslog | grep error
Parsing Fields from Files
Many files are structured with delimiters (CSV, colon-separated, etc.). Learn to parse these efficiently using IFS, cut, and awk.
Click Run to execute your code
IFS (Internal Field Separator)
# Parse comma-separated values
while IFS=, read -r field1 field2 field3; do
echo "Fields: $field1, $field2, $field3"
done < data.csv
# Parse colon-separated (like /etc/passwd)
while IFS=: read -r user pass uid gid desc home shell; do
echo "User $user has shell $shell"
done < /etc/passwd
IFS=- Set delimiter forreadcut -d',' -f1- Extract specific fieldawk -F',' '{print $1}'- More powerful field extractiontr ',' '\n'- Transform delimiters
Reading from Other Sources
Beyond regular files, you can read from command output, URLs, and special files.
# Read from command output (process substitution)
while read -r line; do
echo "Process: $line"
done < <(ps aux | head -5)
# Read multiple files
for file in *.txt; do
while read -r line; do
echo "[$file] $line"
done < "$file"
done
# Read from here document
while read -r line; do
echo "Config: $line"
done </dev/null | xxd
read -r to prevent backslash interpretation. For binary data, consider using dd or xxd instead of text-based tools.
Common Mistakes
1. Forgetting -r in read
# Wrong - backslashes are interpreted
while read line; do echo "$line"; done
# Correct - backslashes preserved
while IFS= read -r line; do echo "$line"; done
2. Losing whitespace
# Wrong - leading/trailing spaces lost
while read line; do echo "$line"; done
# Correct - IFS= preserves whitespace
while IFS= read -r line; do echo "$line"; done
3. Reading file in subshell (variable scope)
# Wrong - count stays 0 (subshell)
count=0
cat file.txt | while read line; do ((count++)); done
echo "$count" # Still 0!
# Correct - no subshell with redirection
count=0
while read -r line; do ((count++)); done < file.txt
echo "$count" # Correct count
4. Not checking if file exists
# Wrong - error if file doesn't exist
while read -r line; do echo "$line"; done < missing.txt
# Correct - check first
if [[ -f "file.txt" ]]; then
while read -r line; do echo "$line"; done < "file.txt"
else
echo "File not found!"
fi
Exercise: Log File Analyzer
Task: Create a script that analyzes a log file!
Requirements:
- Count total number of lines
- Count lines containing "error" (case-insensitive)
- Display the first and last 3 lines
- Parse and display unique IP addresses (first field)
Show Solution
#!/bin/bash
# Log File Analyzer
# Create sample log file
log_file="/tmp/access.log"
cat > "$log_file" << 'EOF'
192.168.1.1 - - [01/Jan/2024] "GET /index.html" 200
192.168.1.2 - - [01/Jan/2024] "GET /error.html" 404
192.168.1.1 - - [01/Jan/2024] "POST /api" 500 Error
10.0.0.1 - - [01/Jan/2024] "GET /about.html" 200
192.168.1.3 - - [01/Jan/2024] "GET /contact" 200
10.0.0.1 - - [01/Jan/2024] "GET /error" 500 Error
EOF
echo "=== Log File Analysis ==="
echo "File: $log_file"
echo ""
# Count total lines
total=$(wc -l < "$log_file")
echo "Total lines: $total"
# Count error lines (case-insensitive)
errors=$(grep -ic "error" "$log_file")
echo "Lines with 'error': $errors"
echo ""
# First and last 3 lines
echo "--- First 3 lines ---"
head -n 3 "$log_file"
echo ""
echo "--- Last 3 lines ---"
tail -n 3 "$log_file"
echo ""
# Unique IPs (first field)
echo "--- Unique IP Addresses ---"
cut -d' ' -f1 "$log_file" | sort -u
# Cleanup
rm -f "$log_file"
Summary
- cat: Read entire file into variable or output
- while read: Process file line by line (
while IFS= read -r line) - mapfile: Read file into array (
mapfile -t arr < file) - head/tail: Read first/last N lines, or follow file changes
- IFS: Set field delimiter for parsing structured data
- cut/awk: Extract specific fields from delimited data
- Always use:
IFS= read -rto preserve whitespace and backslashes
What's Next?
Now that you can read files, let's learn how to write files. You'll discover how to create files, append content, use printf for formatted output, and safely write to files without data loss!
Enjoying these tutorials?