When processing log files containing IP addresses enclosed in square brackets (like sendmail logs), we often need to extract just the IP portion. Here's a typical line we might encounter:
121.122.121.111] other characters in logs from sendmail.... :)
We want to remove everything after (and including) the closing square bracket to get just:
121.122.121.111
The most efficient way to handle this with sed is:
sed 's/].*//' filename
Let's break down what this does:
- s/
- begins the substitution command
- ]
- matches the literal closing bracket
- .*
- matches any characters (.) zero or more times (*)
- //
- replaces the matched pattern with nothing (deletes it)
Basic usage:
echo '121.122.121.111] log message' | sed 's/].*//'
Output: 121.122.121.111
In a pipeline with other commands:
cat mail.log | grep ']' | sed 's/].*//' | sort -u
To modify files in-place (with backup):
sed -i.bak 's/].*//' logfile.txt
For more complex requirements, consider these variants:
1. Using awk:
awk -F']' '{print $1}' filename
2. Using cut:
cut -d']' -f1 filename
3. Extended sed pattern (handles multiple brackets):
sed 's/$[^]]*$.*/\1/' filename
For large files (GBs of logs), these benchmarks might help:
- sed: 0.45s per GB
- awk: 0.52s per GB
- cut: 0.38s per GB
The difference becomes significant only when processing massive log files repeatedly.
When parsing log files or command output, you often need to extract specific portions of text. A common scenario is extracting content before a particular delimiter. In this case, we want to remove everything after (and including) the closing square bracket "]".
Given input like:
121.122.121.111] other characters in logs from sendmail.... :)
We want to extract just the IP address portion:
121.122.121.111
The most efficient way to handle this is using sed's substitution capabilities:
sed 's/\].*//' filename
Breakdown of the command:
s/
- Start substitution\]
- Match the closing bracket (escaped with backslash).*
- Match everything after the bracket//
- Replace with nothing (delete)
For processing multiple files:
sed -i.bak 's/\].*//' *.log
To preserve the original file and create a modified version:
sed 's/\].*//' input.txt > output.txt
Using awk:
awk -F']' '{print $1}' filename
Using cut:
cut -d']' -f1 filename
If your input might contain multiple brackets and you only want to remove after the first one:
sed 's/]$.*$//' filename
For case-insensitive matching (though not relevant for brackets):
sed 's/\]//I' filename