~75 minutes. Write analyze.sh: a script that takes a filename argument, checks it exists, and prints a line/word/character summary.
Goal: write a well-structured bash script with argument checking, file validation, and formatted output. The script must handle errors gracefully.
Estimated time: 75 minutes
Prerequisites: Week 9 lecture (variables, conditionals, positional parameters, wc command)
Part A: Minimal version
Create analyze.sh in ~/fnd-101/lab-9-1/:
mkdir -p ~/fnd-101/lab-9-1
cd ~/fnd-101/lab-9-1
Write the following script:
#!/bin/bash
# analyze.sh -- file statistics summary
if [ "$#" -eq 0 ]; then
echo "Usage: $0 <filename>"
exit 1
fi
FILE="$1"
if [ ! -f "$FILE" ]; then
echo "Error: '$FILE' not found or is not a regular file"
exit 1
fi
LINES=$(wc -l < "$FILE")
WORDS=$(wc -w < "$FILE")
CHARS=$(wc -c < "$FILE")
echo "File: $FILE"
echo "Lines: $LINES"
echo "Words: $WORDS"
echo "Bytes: $CHARS"
Make it executable:
chmod +x analyze.sh
Part B: Test on two different files
Run analyze.sh on at least two different files:
./analyze.sh sample/logs/access.log
./analyze.sh sample/docs/annual-report.txt
Record the output for both runs in your notes.
Part C: Test error handling
-
Run the script with no arguments:
./analyze.sh. Does it print the usage message and exit? -
Run it on a file that does not exist:
./analyze.sh nonexistent.txt. Does it print the error message? -
Run it on a directory:
./analyze.sh sample/. What happens? (A directory is not a regular file, so[ ! -f "$FILE" ]should catch it.)
Part D: Add an ERROR count feature
Extend the script to count lines containing the string "ERROR" (case-insensitive) when the --count-errors flag is passed as the second argument:
if [ "$2" = "--count-errors" ]; then
ERRORS=$(grep -ic "error" "$FILE")
echo "Lines with 'error' (case-insensitive): $ERRORS"
fi
Test:
./analyze.sh sample/logs/error.log --count-errors
(Create sample/logs/error.log first if you have not already, from Lab 8.2.)
Part E: Make the output nicer
Add a separator line and a file size:
SIZE=$(du -h "$FILE" | cut -f1)
echo "=========================="
echo "File: $FILE"
echo "Size: $SIZE"
echo "Lines: $LINES"
echo "Words: $WORDS"
echo "Bytes: $CHARS"
echo "=========================="
(du -h gives a human-readable size like "4.0K"; cut -f1 takes just the size field.)
Expected output / artifact
lab-9-1/analyze.sh (the completed script, with all extensions from Parts A-E)
Also: lab-9-1/test-output.txt showing the output of running the script on 3 different inputs (good file, missing file, directory).
git add lab-9-1/
git commit -m "lab-9-1: analyze.sh bash script with error handling"
Common pitfalls
- Spaces around
=in test:[ "$#" -eq 0 ]is correct;[$# -eq 0]without spaces will fail - Quoting
$FILE: always quote variables that might contain spaces:"$FILE"not$FILE. A filename like "my file.txt" will break an unquoted command. wc -l < "$FILE"vswc -l "$FILE": the<redirection removes the filename fromwc's output. Without<, wc prints " 5 filename" instead of just " 5". Use the redirection for cleaner output.- exit codes:
exit 1signals failure to the caller;exit 0signals success. Scripts that exit 0 on error confuse other programs that check exit codes.
Stretch (optional)
Add a --help flag that prints a multi-line usage description:
if [ "$1" = "--help" ] || [ "$1" = "-h" ]; then
cat << 'EOF'
analyze.sh -- file statistics
Usage: analyze.sh <filename> [--count-errors]
Options:
--count-errors also count lines containing 'error' (case-insensitive)
--help, -h show this help
EOF
exit 0
fi
Lab 9.1 v0.1.