On this page

The tools in this chapter turn text into structured data. They are the building blocks of the Unix philosophy: each one does one thing well, and they are connected with pipes (|).

grep — search for text

grep prints lines that match a pattern.

$ grep apple fruits.txt
apple
apple
apple

Common flags:

Flag Meaning
-i case-insensitive
-n show line numbers
-c count matching lines instead of printing
-v invert: print lines that do NOT match
-r search recursively through directories
-l print only the names of matching files (not the lines)
$ grep -n apple fruits.txt
1:apple
4:apple
6:apple

grep -r searches a whole directory tree:

$ grep -r "error" /var/log/

Combine -r and -l to list which files contain a match, without printing the lines themselves:

$ grep -rl "error" /var/log/

sed — stream editor

sed edits text line by line. The most common use is find-and-replace.

$ sed "s/apple/pear/" fruits.txt
pear
banana
cherry

sed only changes the first match per line; add g to replace all:

$ sed "s/apple/pear/g" fruits.txt

Print a specific line with -n and a line address:

$ sed -n "2p" fruits.txt
banana

Delete a line with d:

$ sed "2d" fruits.txt

To edit a file in place (no output to screen), use -i:

$ sed -i "s/cherry/peach/" fruits.txt

Careful: sed -i overwrites the original file — make a backup with -i.bak if you are unsure.

awk — field-based processing

awk works on lines split into fields. By default fields are separated by whitespace and numbered from $1.

$ printf "alice 10\nbob 20\n" | awk '{print $1}'
alice
bob

(printf prints with escapes — \n is a newline. It is the predictable cousin of the echo -e from Chapter 4, and the traditional choice inside pipelines.)

Print a column by number:

$ awk '{print $2}' scores.txt

With a custom separator, use -F:

$ echo "a:b:c" | awk -F: '{print $2}'
b

awk can compute over lines with END:

$ awk '{sum += $2} END {print sum}' scores.txt
30

cut — extract columns

cut pulls out fields by delimiter. Specify the delimiter with -d and the fields with -f:

$ printf "a,b,c\nd,e,f\n" | cut -d, -f2
b
e

sort — order lines

sort orders lines alphabetically.

$ sort fruits.txt
apple
apple
apple
banana
Flag Meaning
-n numeric sort
-r reverse
-h human-numeric: 2K sorts before 1M (pairs with du -h)
-k sort by a specific column
$ sort -n numbers.txt
$ sort -r fruits.txt

uniq — remove duplicates

uniq removes adjacent duplicate lines. Since duplicates are usually not adjacent, it is almost always combined with sort:

$ sort fruits.txt | uniq
apple
banana
cherry
date

Count occurrences with -c:

$ sort fruits.txt | uniq -c
      3 apple
      1 banana
      1 cherry
      1 date

wc — word count

wc counts lines, words and bytes.

$ wc fruits.txt
 6  6 37 fruits.txt

Use -l for lines only:

$ wc -l fruits.txt
6 fruits.txt

A common pattern: count how many files are in a directory:

$ ls | wc -l

More text tools

A few more tools that appear everywhere in shell workflows:

diff shows the differences between two files:

$ diff old.txt new.txt

tac prints a file in reverse line order (it is cat backwards):

$ tac notes.txt

nl numbers the lines of a file:

$ nl notes.txt
     1  first line
     2  second line

tr translates characters — swap one set for another, or squeeze repeats down to one:

$ echo hello | tr a-z A-Z
HELLO
$ echo "a  b  c" | tr -s " "
a b c

column -t aligns columns of text into a neat table:

$ printf "alice 10\nbob 20\n" | column -t
alice  10
bob    20

watch re-runs a command repeatedly and shows the changing output on screen — handy to watch a value over time:

$ watch free -h

Press Ctrl+C to stop watch.

comm compares two sorted files, showing lines unique to each and lines in both:

$ comm sorted1.txt sorted2.txt

xargs turns its standard input into arguments for another command. It is the power tool for acting on a list of items, such as files found by find:

$ find . -name "*.log" | xargs rm

Putting it together

These tools compose naturally. For example, the five most common words in a file:

$ tr -s ' ' '\n' < guide.txt | sort | uniq -c | sort -nr | head -5

Reading it left to right: tr turns every space into a newline (one word per line), and the < feeds guide.txt into it — input redirection, chapter 13’s > with the arrow flipped. Then sort puts neighbouring words together, uniq -c counts them, and sort -nr orders by count.