scores.txtana 7 passben 3 failcy 9 passdee 4 failterminal$ grep fail scores.txt |> sed 's/fail/retry/' |> awk '{ print $1, $3 }'ben retrydee retrystdinstdoutgrepfailstdinstdoutseds/fail/retry/stdinstdoutawkprint $1, $3$1$2$3ana 7 passben 3 failben 3 retryben retrycy 9 passdee 4 faildee 4 retrydee retrybendee34retryretry
Back: the file scores.txt and the terminal. Front: grep, sed and awk, joined by pipesPlates: each program's stdin (left) and stdout (right). Cells: awk's fields $1, $2, $3Tokens: the lines of text flowing through the pipeline, and the fields awk splits outThe file scores.txt at the back left, the terminal at the back right. In front, three programs joined by pipes: grep keeps the lines that contain fail, sed changes fail to retry, and awk splits each line into fields and prints the first and third. Each line is a token: watch two of the four lines survive grep, change in sed, split in awk, and reach the terminal as ben retry and dee retry. A pipe carries stdout only. Error messages go to stderr, which still reaches the terminal, so you see them even in the middle of a pipeline.

Lines and streams

  1. Linux text tools treat a file as a list of lines. Our file, scores.txt, has 4 lines. Each line holds a name, a score and a result, separated by spaces. The job: list everyone who must retry.

grep, then sed

awk and the answer

What happens

;; step 1/10 · lines
scores.txt   4 lines, one person per line
  line 1   ana 7 pass
  line 2   ben 3 fail
  line 3   cy 9 pass
  line 4   dee 4 fail
each line   name  score  result
goal        who failed, and must retry?

Without the g flag (s/fail/retry/g), sed replaces only the first match on each line. Careful: sed -i writes the change back into the file and overwrites it, so try the command without -i first and keep a copy. A pipe carries stdout only. Error messages go to stderr, which still reaches the terminal, so you see them even in the middle of a pipeline.