Advanced sed Commands and Pattern Matching
Now that we've mastered basic substitution and in-place editing with sed
, let's explore some more advanced features:
- Using different delimiters
- Using address ranges to target specific lines
- Combining multiple commands
Using Different Delimiters
While we've been using the forward slash /
as the delimiter in our substitution commands, sed
allows us to use any character as a delimiter. This is especially useful when the pattern or replacement text contains slashes.
Let's create a file with file paths:
echo "/usr/local/bin is in the PATH" > ~/project/paths.txt
echo "My config is in /etc/myapp/config.json" >> ~/project/paths.txt
If we want to replace /usr/local/bin
with /opt/bin
, using slashes would be confusing:
sed 's/\/usr\/local\/bin/\/opt\/bin/' ~/project/paths.txt
Instead, we can use a different delimiter, such as #
:
sed 's#/usr/local/bin#/opt/bin#' ~/project/paths.txt
This is much more readable! The output should be:
/opt/bin is in the PATH
My config is in /etc/myapp/config.json
Other common delimiters include |
, :
, and _
.
Addressing - Targeting Specific Lines
sed
allows us to specify which lines to apply the substitution to. This is done by prefixing the command with an address.
Let's create a new file with numbered lines:
echo "Line 1: This is the first line." > ~/project/numbered.txt
echo "Line 2: This is the second line." >> ~/project/numbered.txt
echo "Line 3: This is the third line." >> ~/project/numbered.txt
echo "Line 4: This is the fourth line." >> ~/project/numbered.txt
echo "Line 5: This is the fifth line." >> ~/project/numbered.txt
To replace "line" with "row" only on line 3:
sed '3 s/line/row/' ~/project/numbered.txt
The output should be:
Line 1: This is the first line.
Line 2: This is the second line.
Line 3: This is the third row.
Line 4: This is the fourth line.
Line 5: This is the fifth line.
We can also specify a range of lines. To replace "line" with "row" on lines 2 through 4:
sed '2,4 s/line/row/' ~/project/numbered.txt
The output should be:
Line 1: This is the first line.
Line 2: This is the second row.
Line 3: This is the third row.
Line 4: This is the fourth row.
Line 5: This is the fifth line.
Another useful feature is the ability to match lines based on a pattern. For example, to replace "line" with "row" only on lines that contain "third" or "fourth":
sed '/\(third\|fourth\)/ s/line/row/' ~/project/numbered.txt
The output should be:
Line 1: This is the first line.
Line 2: This is the second line.
Line 3: This is the third row.
Line 4: This is the fourth row.
Line 5: This is the fifth line.
Combining Multiple Commands
We can combine multiple sed
commands using the -e
option or by separating commands with semicolons.
Let's replace "first" with "1st", "second" with "2nd", and "third" with "3rd" in a single command:
sed -e 's/first/1st/' -e 's/second/2nd/' -e 's/third/3rd/' ~/project/numbered.txt
Alternatively, we can use semicolons:
sed 's/first/1st/; s/second/2nd/; s/third/3rd/' ~/project/numbered.txt
Both commands should produce the same output:
Line 1: This is the 1st line.
Line 2: This is the 2nd line.
Line 3: This is the 3rd line.
Line 4: This is the fourth line.
Line 5: This is the fifth line.
Let's now make these changes permanent:
sed -i 's/first/1st/; s/second/2nd/; s/third/3rd/' ~/project/numbered.txt
And verify the changes:
cat ~/project/numbered.txt
You should see the updated text with ordinal numbers.