C.2. Awk

Awk [1] 是一种全功能的文本处理语言,其语法让人联想到 C 语言。 虽然它拥有大量的运算符和功能,但我们在这里只介绍其中一小部分 - 那些在 shell 脚本中最有用的部分。

Awk 将传递给它的输入的每一行分解为 字段。 默认情况下,字段是由 空白字符 分隔的连续字符字符串,尽管有一些选项可以更改这一点。 Awk 解析并操作每个单独的字段。 这使得它非常适合处理结构化文本文件 -- 尤其是表格 -- 数据组织成一致的块,例如行和列。

强引用花括号 将 awk 代码块包含在 shell 脚本中。

# $1 is field #1, $2 is field #2, etc.

echo one two | awk '{print $1}'
# one

echo one two | awk '{print $2}'
# two

# But what is field #0 ($0)?
echo one two | awk '{print $0}'
# one two
# All the fields!


awk '{print $3}' $filename
# Prints field #3 of file $filename to stdout.

awk '{print $1 $5 $6}' $filename
# Prints fields #1, #5, and #6 of file $filename.

awk '{print $0}' $filename
# Prints the entire file!
# Same effect as:   cat $filename . . . or . . . sed '' $filename

我们刚刚看到了 awk 的 print 命令的实际应用。 我们在这里需要处理的 awk 的另一个特性是变量。 Awk 处理变量的方式与 shell 脚本类似,但更加灵活一些。

{ total += ${column_number} }
这会将以下值加到column_number运行总计total>。 最后,要打印 "total",有一个 END 命令块,它在脚本处理完所有输入后执行。
END { print total }

END 相对应,还有一个 BEGIN,用于在 awk 开始处理其输入之前执行的代码块。

以下示例说明了 awk 如何向 shell 脚本添加文本解析工具。

示例 C-1. 统计字母出现次数

#! /bin/sh
# letter-count2.sh: Counting letter occurrences in a text file.
#
# Script by nyal [nyal@voila.fr].
# Used in ABS Guide with permission.
# Recommented and reformatted by ABS Guide author.
# Version 1.1: Modified to work with gawk 3.1.3.
#              (Will still work with earlier versions.)


INIT_TAB_AWK=""
# Parameter to initialize awk script.
count_case=0
FILE_PARSE=$1

E_PARAMERR=85

usage()
{
    echo "Usage: letter-count.sh file letters" 2>&1
    # For example:   ./letter-count2.sh filename.txt a b c
    exit $E_PARAMERR  # Too few arguments passed to script.
}

if [ ! -f "$1" ] ; then
    echo "$1: No such file." 2>&1
    usage                 # Print usage message and exit.
fi 

if [ -z "$2" ] ; then
    echo "$2: No letters specified." 2>&1
    usage
fi 

shift                      # Letters specified.
for letter in `echo $@`    # For each one . . .
  do
  INIT_TAB_AWK="$INIT_TAB_AWK tab_search[${count_case}] = \
  \"$letter\"; final_tab[${count_case}] = 0; " 
  # Pass as parameter to awk script below.
  count_case=`expr $count_case + 1`
done

# DEBUG:
# echo $INIT_TAB_AWK;

cat $FILE_PARSE |
# Pipe the target file to the following awk script.

# ---------------------------------------------------------------------
# Earlier version of script:
# awk -v tab_search=0 -v final_tab=0 -v tab=0 -v \
# nb_letter=0 -v chara=0 -v chara2=0 \

awk \
"BEGIN { $INIT_TAB_AWK } \
{ split(\$0, tab, \"\"); \
for (chara in tab) \
{ for (chara2 in tab_search) \
{ if (tab_search[chara2] == tab[chara]) { final_tab[chara2]++ } } } } \
END { for (chara in final_tab) \
{ print tab_search[chara] \" => \" final_tab[chara] } }"
# ---------------------------------------------------------------------
#  Nothing all that complicated, just . . .
#+ for-loops, if-tests, and a couple of specialized functions.

exit $?

# Compare this script to letter-count.sh.

有关 shell 脚本中 awk 的更简单示例,请参阅

  1. 示例 15-14

  2. 示例 20-8

  3. 示例 16-32

  4. 示例 36-5

  5. 示例 28-2

  6. 示例 15-20

  7. 示例 29-3

  8. 示例 29-4

  9. 示例 11-3

  10. 示例 16-61

  11. 示例 9-16

  12. 示例 16-4

  13. 示例 10-6

  14. 示例 36-19

  15. 示例 11-9

  16. 示例 36-4

  17. 示例 16-53

  18. 示例 T-3

这就是我们在这里要介绍的关于 awk 的全部内容,各位,但还有很多东西要学习。 请参阅 参考书目 中的相关参考资料。

注释

[1]

它的名字来源于其作者 Aho、Weinberg 和 Kernighan 姓氏的首字母。