Hello! Let's continue our journey into advanced Bash scripting.
In the previous lesson, we mastered grep and regular expressions, learning how to filter text streams and extract specific information. This skill is essential for searching through logs and outputs. But what if you need to change the text as it flows by, not just find it?
This lesson introduces sed, the stream editor. Your learning outcome is to perform stream-based text transformations using sed for substitution, deletion, and insertion. While grep is your magnifying glass for finding things, sed is your surgical tool for modifying them on the fly. This is a core skill for automating configuration changes, cleaning up data, and preparing text for further processing in your scripts.
1. The Core of sed: Substitution
The most common use of sed is to substitute text. The command for this is s, and its basic syntax is s/pattern/replacement/flags. sed reads input line by line, applies your command, and prints the result to standard output.
Let's break down the key components.
# A simple example:
# This replaces the *first* occurrence of 'error' with 'warning' on each line
echo "An error occurred. This is a critical error." | sed 's/error/warning/'
# Output: An warning occurred. This is a critical error.
Notice only the first "error" was replaced. To change all instances on a line, you need the global flag (g).
echo "An error occurred. This is a critical error." | sed 's/error/warning/g'
# Output: An warning occurred. This is a critical warning.
This video provides an excellent walkthrough of sed's fundamental commands, with a great focus on substitution.
LCL 30 - sed - Linux Command Line tutorial for forensics
The video 'LCL 30 - sed - Linux Command Line tutorial' gives a clear and practical introduction to sed, starting with what it is and then diving into its most powerful command: substitution.
Please watch the following two segments: What is sed? (00:12 - 01:04): This introduces sed as a stream editor. Substitution (07:05 - 09:43): This is the core of the lesson. Pay close attention to the s command, the use of flags like g (global) and i (case-insensitive), and how to replace specific occurrences.
A common challenge in DevOps is dealing with file paths, which contain slashes (/). Since sed uses / as a delimiter by default, this creates a messy command requiring you to escape every slash.
sed 's/\/var\/log\/nginx/\/data\/logs\/nginx/g' config.file
A much cleaner way is to use an alternative delimiter. You can use almost any character after the s. Common choices are |, #, or @.
sed 's|/var/log/nginx|/data/logs/nginx|g' config.file
2. Deleting Lines
Substitution is about changing text within a line. The d command is for deleting an entire line. You can specify which lines to delete by number, a range, or, most powerfully, a pattern.
This is extremely useful for cleaning up configuration files or logs before processing them.
- Delete by line number:
sed '3d' file.txt(deletes the 3rd line) - Delete by range:
sed '1,5d' file.txt(deletes lines 1 through 5) - Delete lines matching a pattern:
sed '/pattern/d' file.txt
Let's see this in a practical context. Imagine you want to process a configuration file but ignore all comments (lines starting with #) and all empty lines.
# Example config.conf
# This is a database configuration
db.host=localhost
db.port=5432
# Enable connection pooling
pool.enabled=true
You could clean this with two sed commands:
sed '/^#/d' config.confremoves comment lines. (^matches the start of the line).sed '/^$/d' config.confremoves empty lines. ($matches the end of the line, so^$matches a line with nothing between the start and end).
You can combine these using a semicolon ; to perform both actions in one pass:
sed '/^#/d; /^$/d' config.conf
# Output:
# db.host=localhost
# db.port=5432
# pool.enabled=true
3. Inserting and Appending Lines
Besides substitution and deletion, sed can also add new lines to the stream.
- The
icommand inserts text before a matched line. - The
acommand appends text after a matched line.
The syntax is sed '/pattern/i \new text' or sed '/pattern/a \new text'.
This is perfect for programmatically adding settings to a configuration file. For instance, to add a timeout setting right after db.port in our example config.conf:
sed '/db.port/a db.timeout=30s' config.conf
# Output:
# # This is a database configuration
# db.host=localhost
# db.port=5432
# db.timeout=30s
#
# # Enable connection pooling
# pool.enabled=true
For a consolidated view of these core operations, refer to this excellent cheat sheet.

4. Practical Scenario: Editing a Configuration File
By default, sed prints its output to the console. To save the changes, you can either redirect the output to a new file or edit the file in-place using the -i flag.
⚠️ Warning: Using sed -i without a backup is destructive. It overwrites the original file. A safer practice is to create a backup by providing an extension to the -i flag, like sed -i.bak .... This performs the in-place edit on the original file and saves a copy of the original with a .bak extension.
Let's combine everything we've learned into a single, practical task. Imagine you have a docker-compose.yml file and you need to automate an update for a new environment.
Starting docker-compose.yml:
version: '3.8'
services:
webapp:
# image: myapp:1.0
image: myapp:latest
ports:
- "80:8080"
environment:
- DB_HOST=localhost
- FEATURE_FLAG_ALPHA=false
Your task is to write a single sed command that:
- Changes the
DB_HOSTfromlocalhosttopostgres.prod.svc.cluster.local. - Uncomments the line for
image: myapp:1.0and comments outimage: myapp:latest. - Changes
FEATURE_FLAG_ALPHAfromfalsetotrue. - Performs these changes in-place and creates a backup file named
docker-compose.yml.bak.
Here is the solution. We use the -e option to chain multiple expressions.
sed -i.bak \
-e 's/DB_HOST=localhost/DB_HOST=postgres.prod.svc.cluster.local/' \
-e '/image: myapp:1.0/s/^# //' \
-e '/image: myapp:latest/s/^/# /' \
-e 's/FEATURE_FLAG_ALPHA=false/FEATURE_FLAG_ALPHA=true/' \
docker-compose.yml
Let's dissect this powerful one-liner:
sed -i.bak: Edit in-place and create a backup.-e 's/DB_HOST=...': A standard substitution for the database host.-e '/image: myapp:1.0/s/^# //': An addressed substitution. It first finds the line containingimage: myapp:1.0(/pattern/), then on that line only, it performs the substitutions/^# //, which finds a hash and a space at the beginning of the line (^#) and replaces it with nothing.-e '/image: myapp:latest/s/^/# /': Similar logic, but this time it adds a comment by replacing the start of the line (^) with#.-e 's/FEATURE_FLAG_ALPHA=...': Another simple substitution.
This example showcases the kind of powerful, automated text manipulation that is central to DevOps. For more practical examples, the following article is an excellent resource.
Sed One-Liners: 30 Commands from 2TB/Month Log Analysis
The article 'Sed One-Liners: 30 Commands' provides a fantastic collection of practical, real-world sed commands. It's less about the theory and more about the application.
Skim through these sections to get a feel for how sed is used in the wild: Patterns 1-5 (Basic Substitution): Note the use of alternative delimiters in Pattern 5. Line Deletion and Insertion (Patterns 11-18): Pay attention to the examples for removing comments and empty lines. Real-World Examples: The 'Updating Configuration Files' example is very similar to what we just did and reinforces the concepts.
Conclusion
You have now learned how to use sed to perform the three fundamental stream-editing operations. This tool allows you to programmatically modify files and data streams, a crucial capability for any DevOps engineer.
Key Takeaways:
sedtransforms text streams, distinguishing it fromgrepwhich only filters them.- The most common commands are
s(substitute),d(delete),i(insert), anda(append). - Substitution flags like
g(global) andi(case-insensitive) are essential. - Use alternative delimiters (e.g.,
s|...|...|) to cleanly handle patterns containing slashes. - Address your commands by line number (
10s/.../) or pattern (/pattern/d) to target specific lines. - The
-iflag modifies files in-place; always consider using-i.bakfor safety.
Preview of the Next Lesson:sed is brilliant for line-oriented edits. But what if your data is structured in columns, like a CSV file or the output of ls -l? For that, we need a tool that understands fields. In our next lesson, we will explore awk, a powerful utility designed to extract and format structured, column-based text data.