C.2. Awk

Awk [1] is a full-featured text processing language with a syntax reminiscent of C. While it possesses an extensive set of operators and capabilities, we will cover only a few of these here - the ones most useful in shell scripts.

Awk breaks each line of input passed to it into fields. By default, a field is a string of consecutive characters delimited by whitespace, though there are options for changing this. Awk parses and operates on each separate field. This makes it ideal for handling structured text files -- especially tables -- data organized into consistent chunks, such as rows and columns.

Strong quoting and curly brackets enclose blocks of awk code within a shell script.

   1 # $1 is field #1, $2 is field #2, etc.
   2 
   3 echo one two | awk '{print $1}'
   4 # one
   5 
   6 echo one two | awk '{print $2}'
   7 # two
   8 
   9 # But what is field #0 ($0)?
  10 echo one two | awk '{print $0}'
  11 # one two
  12 # All the fields!
  13 
  14 
  15 awk '{print $3}' $filename
  16 # Prints field #3 of file $filename to stdout.
  17 
  18 awk '{print $1 $5 $6}' $filename
  19 # Prints fields #1, #5, and #6 of file $filename.
  20 
  21 awk '{print $0}' $filename
  22 # Prints the entire file!
  23 # Same effect as:   cat $filename . . . or . . . sed '' $filename

We have just seen the awk print command in action. The only other feature of awk we need to deal with here is variables. Awk handles variables similarly to shell scripts, though a bit more flexibly.

   1 { total += ${column_number} }
This adds the value of column_number to the running total of total>. Finally, to print "total", there is an END command block, executed after the script has processed all its input.
   1 END { print total }

Corresponding to the END, there is a BEGIN, for a code block to be performed before awk starts processing its input.

The following example illustrates how awk can add text-parsing tools to a shell script.


Example C-1. Counting Letter Occurrences

   1 #! /bin/sh
   2 # letter-count2.sh: Counting letter occurrences in a text file.
   3 #
   4 # Script by nyal [nyal@voila.fr].
   5 # Used in ABS Guide with permission.
   6 # Recommented and reformatted by ABS Guide author.
   7 # Version 1.1: Modified to work with gawk 3.1.3.
   8 #              (Will still work with earlier versions.)
   9 
  10 
  11 INIT_TAB_AWK=""
  12 # Parameter to initialize awk script.
  13 count_case=0
  14 FILE_PARSE=$1
  15 
  16 E_PARAMERR=85
  17 
  18 usage()
  19 {
  20     echo "Usage: letter-count.sh file letters" 2>&1
  21     # For example:   ./letter-count2.sh filename.txt a b c
  22     exit $E_PARAMERR  # Too few arguments passed to script.
  23 }
  24 
  25 if [ ! -f "$1" ] ; then
  26     echo "$1: No such file." 2>&1
  27     usage                 # Print usage message and exit.
  28 fi 
  29 
  30 if [ -z "$2" ] ; then
  31     echo "$2: No letters specified." 2>&1
  32     usage
  33 fi 
  34 
  35 shift                      # Letters specified.
  36 for letter in `echo $@`    # For each one . . .
  37   do
  38   INIT_TAB_AWK="$INIT_TAB_AWK tab_search[${count_case}] = \
  39   \"$letter\"; final_tab[${count_case}] = 0; " 
  40   # Pass as parameter to awk script below.
  41   count_case=`expr $count_case + 1`
  42 done
  43 
  44 # DEBUG:
  45 # echo $INIT_TAB_AWK;
  46 
  47 cat $FILE_PARSE |
  48 # Pipe the target file to the following awk script.
  49 
  50 # ---------------------------------------------------------------------
  51 # Earlier version of script:
  52 # awk -v tab_search=0 -v final_tab=0 -v tab=0 -v \
  53 # nb_letter=0 -v chara=0 -v chara2=0 \
  54 
  55 awk \
  56 "BEGIN { $INIT_TAB_AWK } \
  57 { split(\$0, tab, \"\"); \
  58 for (chara in tab) \
  59 { for (chara2 in tab_search) \
  60 { if (tab_search[chara2] == tab[chara]) { final_tab[chara2]++ } } } } \
  61 END { for (chara in final_tab) \
  62 { print tab_search[chara] \" => \" final_tab[chara] } }"
  63 # ---------------------------------------------------------------------
  64 #  Nothing all that complicated, just . . .
  65 #+ for-loops, if-tests, and a couple of specialized functions.
  66 
  67 exit $?
  68 
  69 # Compare this script to letter-count.sh.

For simpler examples of awk within shell scripts, see:

  1. Example 15-14

  2. Example 20-8

  3. Example 16-32

  4. Example 36-5

  5. Example 28-2

  6. Example 15-20

  7. Example 29-3

  8. Example 29-4

  9. Example 11-3

  10. Example 16-61

  11. Example 9-16

  12. Example 16-4

  13. Example 10-6

  14. Example 36-19

  15. Example 11-9

  16. Example 36-4

  17. Example 16-53

  18. Example T-3

That's all the awk we'll cover here, folks, but there's lots more to learn. See the appropriate references in the Bibliography.

Notes

[1]

Its name derives from the initials of its authors, Aho, Weinberg, and Kernighan.