Build the mental model
grep and sed are two of the most reached-for tools in shell scripting, and they solve complementary problems: grep finds lines that match a pattern without changing anything, while sed transforms text as it streams through, most commonly by substituting one piece of text for another. grep's flags turn a plain search into something far more targeted — -i ignores case, -v inverts the match to show lines that don't match, -n prefixes each result with its line number so you know where in the file it came from, -c returns a count instead of the matching lines themselves, and -E switches on extended regular expressions so metacharacters like + and ? work without backslash-escaping them. sed's core operation is the substitution command, s/old/new/, which by default replaces only the first match on each line; appending the g flag makes it replace every match on the line instead, which trips people up constantly because the default behavior is easy to forget. Just as important as the substitution itself is how you apply it: sed with no flags prints the transformed text to stdout, leaving the original file untouched, while sed -i edits the file in place — and sed -i.bak does the same edit while also preserving a .bak copy of the file exactly as it was before, which matters enormously the moment your regex doesn't do quite what you expected.
Connect it to a real scenario
A very common real task is fixing a setting in a configuration file — say, changing a service's port number or toggling a debug flag — from within a deployment script rather than editing the file by hand every time, and this lesson's code walks through the full workflow. It starts by using grep defensively: grep "port" confirms the setting actually exists in the file and shows its current value before anything is changed, grep -i "host" demonstrates that a case-insensitive search would still find HOST even if the file used different capitalization, and grep -v "^#" filters out comment lines to show only the active settings — useful for auditing a config file quickly. grep -En "[0-9]+" combines extended regex with line numbers to show exactly which lines contain digits and where. Once the setting is confirmed, sed "s/port=8080/port=9090/" previews the change by printing the modified text without touching the file, which is a good habit before committing to an in-place edit. The actual edit, sed -i.bak "s/debug=true/debug=false/", flips the debug flag while writing a .bak copy of the original alongside it — so if the regex had matched something unintended, or the wrong file had been targeted, the previous state is one mv command away from being restored instead of being gone for good.
Try the working example
#!/bin/bash
config_file=$(mktemp)
cat > "$config_file" <<EOF
# Server configuration
host=localhost
port=8080
debug=true
timeout=30
EOF
echo "Lines matching 'port':"
grep "port" "$config_file"
echo ""
echo "Case-insensitive search for 'HOST':"
grep -i "host" "$config_file"
echo ""
echo "Lines NOT starting with #:"
grep -v "^#" "$config_file"
echo ""
echo "Count of settings lines (containing =):"
grep -c "=" "$config_file"
echo ""
echo "Lines with a number, using extended regex:"
grep -En "[0-9]+" "$config_file"
echo ""
echo "Replacing port value with sed:"
sed "s/port=8080/port=9090/" "$config_file"
echo ""
echo "Editing the file in place (with a backup):"
sed -i.bak "s/debug=true/debug=false/" "$config_file"
cat "$config_file"
rm -f "$config_file" "$config_file.bak"Running this script prints:
Lines matching 'port':
port=8080
Case-insensitive search for 'HOST':
host=localhost
Lines NOT starting with #:
host=localhost
port=8080
debug=true
timeout=30
Count of settings lines (containing =):
4
Lines with a number, using extended regex:
3:port=8080
5:timeout=30
Replacing port value with sed:
# Server configuration
host=localhost
port=9090
debug=true
timeout=30
Editing the file in place (with a backup):
# Server configuration
host=localhost
port=8080
debug=false
timeout=305-minute try-it
Create a small text file listing a few user names and ages separated by a colon, use grep to find only the lines for users older than a given age prefix pattern, then use sed to change one user's age, keeping a .bak backup of the original file.
One important caution
Using sed -i without a backup suffix on an important file, so a mistyped regex overwrites the only copy with no way to undo it
Forgetting the g flag on sed's substitution, so only the first match on each line gets replaced when every occurrence needed changing
GNU sed Manual — Bash / Shell Scripting