sed
sed is the stream editor.
Tips
OSX Pitfalls
Beware that BSD sed -i requires a mandatory flag for the backup file. You can use -i '' to have no backup file.
Also, OS X sed doesn't support case insensitivity! WTF?! We have to use perl -pe 's/foo/bar/i' foo.txt
or homebrew's gsed
.
Only print a specific line
This will print only the second line of the file
sed -n ' 2{p;q;}' foo.txt
Only print if match
This will perform a replacement and print the result. Use -i
(with caution!) to edit the file at the same time.
sed -n 's/\(127.[0-9]\{1,3\}.[0-9]\{1,3\}.[0-9]\{1,3\}\)/\1 localhost localhost4/p' /etc/hosts
Add a new line with content after a match
Since sed can't insert things like \n, this has to take place on multiple lines, so it's a bit funky looking but still functional.
sed -i "" -e '/respawn/a\
respawn limit 10 5' app_worker_*.conf
Print file starting with first string match
sed -n '/ROUTING TABLE/,$p' /etc/openvpn/openvpn-status.log
Print only lines after a match
The syntax in both of these is <sed_address_one>,<sed_address_two> <action>
$ k describe pod -n moms-iot-oven cookie-baker-2022-proxy |
sed -ne '/^Events/,$ p;'
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Pulling 56m (x1281 over 4d13h) kubelet Pulling image "ubuntu:2004"
Normal BackOff 118s (x29062 over 4d13h) kubelet Back-off pulling image "ubuntu:2004"
That says "Do not print each line by default (-n
). Start at the sed address which is a 'context address' regex /^Events/
, and end at the special sed address $
which means the last line of input, and print those lines. (All of this info is in the man page.)
Or if you don't want to include the match:
sed -e '1,/^Events/ d'
This says "Start at line one and delete every line up to and including the match ^Events
."
Print file contents between two string matches
This will print the contents of the log file between ROUTING TABLE
and GLOBAL STATS
inclusive.
sed -n '/^ROUTING TABLE/,/^GLOBAL STATS/p;/^GLOBAL STATS/q' /etc/openvpn/openvpn-status.log
Or as a bash function
show-contents-between() { sed -n "/$1/,/$2/p;/$2/q"; }
Uncomment a line that matches a regex
This removes the comment and adds wheel to the sudoers list
/bin/sed -i '/^#\s\+%wheel\s\+ALL=(ALL)\s\+ALL$/s/^#\s*//' /etc/sudoers
Delete lines containing a string
sed -i -e '/root/d' asdf.txt
Delete lines not containing a string
sed -i '/foo/!d' wy.txt
Or not containing a MAC address:
sed -i '' -E '/[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}/!d' *
Do a replacement on all files in a dir
sed -i "s/foo/bar/g" /etc/apache2/sites-available/*
Switch all github urls from http to ssh
sed '/url = /s%https?://github.com/\([^/]*/[^/]*\)%git@github.com:\1%' ~/code/*/.git/config
Word boundaries
Normally, word boundaries look like this:
/\bMyWord\b/
or
/\<myword\>/
But in OS X, you have to do them like this:
/[[:<:]]MyWord[[:>:]]/
Which is just ridiculous, so use homebrew's gsed
if you can.
Add a bell to tail
tail -n 0 -f /var/log/messages | sed 's/$/\a'
See Also
- Some great sed tips - http://www-rohan.sdsu.edu/doc/sed.html