Web Analytics

File Reading

Intermediate ~25 min read

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.

Output
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
The while read Pattern: The most common pattern for processing files line by line is:
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.

Output
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
Pro Tip: Use 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.

Output
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
Field Parsing Tools:
  • IFS= - Set delimiter for read
  • cut -d',' -f1 - Extract specific field
  • awk -F',' '{print $1}' - More powerful field extraction
  • tr ',' '\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
Caution: When reading binary files or files with special characters, always use 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 -r to 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!