NAME
Five awk and sed one-liners, taken apart
Five GNU awk and sed one-liners worth memorising, each split into its tokens, plus the sed -i difference on macOS.
SYNOPSIS
DESCRIPTION
Most awk and sed one-liners look like noise until you split them into pieces. Below are five that come up often. Each one gets the command, then a walk through its parts. The examples assume GNU awk and GNU sed, which is what most Linux systems ship. macOS differs in one place, covered at the end.
Print the last field of every line
awk '{print $NF}' notes.txt
awkreads its input one line at a time and runs a program on each line.'{print $NF}'is the program. There is no pattern in front of the braces, so the action runs on every line.- awk splits each line into fields on whitespace by default.
$1is the first field, andNFholds the field count.$NFtherefore means "the field whose number is NF", which is the last one. printwith no argument prints the whole line. With a field, it prints only that field.
This is handy on command output where the number of columns changes from line to line. For example, ls -l | awk '{print $NF}' lists the file names, though it will split names that contain spaces.
List usernames with UID 1000 and up
awk -F: '$3>=1000 {print $1}' /etc/passwd
-F:sets the field separator to a colon. Each line of/etc/passwdis made of colon-separated fields.$3>=1000is a pattern. A pattern placed before the braces decides whether the action runs for that line. Here it checks the third field, the UID, as a number.{print $1}prints the first field, the username.
Regular Linux users start at UID 1000 on most distributions, so this shows them and skips system accounts. It will also list the nobody account, which usually has UID 65534. On macOS the real accounts live in Directory Services and not in this file, so use dscl there instead.
Remove duplicate lines but keep the order
awk '!seen[$0]++' file.txt
- There is no
{}action, so awk falls back to its default action, which is printing the line. seenis an associative array. Reading a key that has never been set gives 0.$0is the whole line, and it is used as the key.seen[$0]++returns the old value and then adds 1. The first time a line appears the old value is 0, so!0is true and the line prints. Every later copy returns 1 or more, so!makes it false and the line is skipped.
sort -u also removes duplicates, but it reorders the output. This version keeps the first occurrence where it was. The tradeoff is memory, since awk keeps every unique line in the array.
Print lines 10 through 20
sed -n '10,20p' file.txt
sedis the stream editor. Like awk, it reads one line at a time.-nturns off sed's default behavior of printing every line.10,20is an address range. It matches line 10 through line 20, inclusive.pis the print command. It prints whatever the address selects.
Put together, -n plus p prints only the selected range. Without -n, the whole file would print, and lines 10 through 20 would appear twice. On a big file, add a quit so sed stops reading: sed -n '10,20p;20q' file.txt.
Replace text in place and keep a backup
sed -i.bak 's/old/new/g' file.txt
-i.bakedits the file in place. The text attached to-iis a backup suffix. sed saves the original asfile.txt.bakand writes the result tofile.txt.s/old/new/is the substitute command.oldis a regular expression, andnewis the replacement text.- The trailing
gflag replaces every match on each line. Without it, only the first match on each line changes. file.txtis the file to edit.
Remember that old is a regex, so characters such as ., * and [ have special meaning. Escape them with a backslash when you want them literal.
The macOS difference
macOS ships BSD sed, and its -i takes the backup suffix as a separate argument. An empty argument means no backup:
sed -i '' 's/old/new/g' file.txt # edit in place, no backup
sed -i .bak 's/old/new/g' file.txt # edit in place, keep file.txt.bak
On GNU sed, the attached form -i.bak is the right one. On BSD sed, a plain -i with no suffix takes the script as the suffix and fails with a confusing error about a missing file. Test any -i command on a copy of the file first, because it changes the original immediately.