Shell 命令之 awk

1. wiki

awk 可以理解一种编程语言,其对输入数据的每一行都进行文本处理,并内建一些数据结构和函数,在熟悉者手中十分灵活

2. 语法

基本语法框架为,其由选项、脚本和输入的数据等组成

1
awk [options] '[scripts]' [files]

1. options

常用的选项主要有 3 个,更多选项可以使用 --help 查看

  • -f [progfile] , --file=[progfile] : 从脚本文件 progfile 中读取事先写好的 awk 命令
  • -F [fs] , --field-separator=[fs] : 指定输入中的分隔符,fs 可以是字符串或正则表达式,特殊字符可以使用转义
  • -v [var=value] , --asign=[var=value] : 给自定义变量赋值,将外部变量传递给 awk

2. scripts

基本语法结构为,脚本通常由模式和命令两部分组成,可以省略其一,但不能同时被省略,其包裹在单引号 '' 或双引号 "" 中。注意,与 shell 的用法一致,在使用单引号 '' 时,变量不会被解释,双引号 "" 中变量则会被替换成相应结果

1
pattern{commands}

1. 模式

模式可以是很多种,一般情况下,每碰到一个使模式表达式为真的输入行,命令就会执行

  • 正则表达式 : 语法为 /r/,支持常用的通配符,也可以使用 exp ~ /r/exp !~ /r/ 表达包含和不包含
  • 逻辑表达式 : 大于(>)、小于(<)、等于(==)、且(&&)、或(||)、否(!)等
  • BEGIN{} : 特殊模式,其不匹配任何输入行,只在开头执行一次,一般用作变量初始化、打印输表头等操作
  • END{} : 特殊模式,其不匹配任何输入行,只在结束执行一次,一般用来打印结果等操作
1
2
3
4
# 读取 : 分隔的文件 passwd,取以 root 或 ftp 开头的行,并打印
awk -F : '/^root|^ftp/{print}' /etc/passwd
# 读取 | 分隔的文件 output.log,取行号大于 3 的行,并打印第行号和第一个字段
awk -F \| 'NR > 3{print NR,$1}' output.log

2. 命令

命令支持很多形式,包括变量或数组赋、内置函数、控制流语句等,其格式也有一定要求:

  • 一行可包含若干条语句,使用分号分开即可
  • 命令的左花括号必须与它的模式在同一行,空行会被忽略
  • 注释可以出现在任意一行的末尾,一个注释以井号 (#) 开始,以换行符结束
  • 一条长语句可以分散成多行,只要在断行处插入一个反斜杠即可

3. 内建变量

awk 会统计一些元数据信息,并存入内建变量中,常用的有

  • $0 : 完整的输入记录
  • $n : 当前记录的由 FS 分隔的第 n 个字段,如 $1 表示第一个字段
  • FS : 字段分隔符,默认是任一空格
  • NR : 表示记录数,在执行过程中对应于当前的行号
  • NF : 表示字段数,在记录被读之后重置为1,如 $NF 为最后一个字段
  • FNR : 同 NR,但相对于当前文件
  • FILENAME : 当前输入文件的名

其他变量的详情,可以使用 man awk 来查看,也可以使用命令 awk --dump-variables '',会将部分可用的变量输出到 awkvars.out 文件中

  • ARGC : 命令行参数的数目。
  • ARGV : 命令行参数数组
  • ARGIND : 命令行中当前文件的位置,主要针对多个文件的输入
  • CONVFMT : 数字转换格式,默认值为 %.6g
  • ERRNO : 最后一个系统错误的描述
  • FIELDWIDTHS : 字段宽度列表,用空格分隔
  • FNR : 同 NR,但相对于当前文件
  • IGNORECASE : 为真,则进行忽略大小写的匹配,默认为假
  • OFMT : 数字的输出格式,默认为 %.6g
  • OFS : 输出字段分隔符,默认为空格
  • ORS : 输出记录分隔符,默认为换行符
  • RS : 记录分隔符,默认为换行符
  • RLENGTH : 由 match 函数所匹配的字符串的长度
  • RSTART : 由 match 函数所匹配的字符串的第一个位置
  • SUBSEP : 数组下标分隔符,默认为 \034

4. 内建函数

1. 字符串函数

  • gsub(Ere, Repl, [ In ] ) : 除了正则表达式所有具体值被替代这点,它和 sub 函数完全一样地执行。
  • index(s, t) : 返回 t 在 s 中出现的位置索引,不存在则返回 0,从 1 开始
  • length ([s]) : 返回字符串 s 的长度,如果没有,则返回整条记录长度($0),数组的话则返回数组元素数量
  • match( String, Ere ) 在 String 参数指定的字符串(Ere 参数指定的扩展正则表达式出现在其中)中返回位置(字符形式),从 1 开始编号,或如果 Ere 参数不出现,则返回 0(零)。RSTART 特殊变量设置为返回值。RLENGTH 特殊变量设置为匹配的字符串的长度,或如果未找到任何匹配,则设置为 -1(负一)。
  • split(s, a [, r [, seps]]) : 使用正则表达式 r 将字符串 s 拆分为数组 a 和分隔符数组 seps,并返回字段数。如果 r 省略,则使用 FS
  • sprintf(fmt, expr-list) : 格式化表达式
  • sub(Ere, Repl, [ In ] ) : 用 Repl 参数指定的字符串替换 In 参数指定的字符串中的由 Ere 参数指定的扩展正则表达式的第一个具体值。sub 函数返回替换的数量。出现在 Repl 参数指定的字符串中的 &(和符号)由 In 参数指定的与 Ere 参数的指定的扩展正则表达式匹配的字符串替换。如果未指定 In 参数,缺省值是整个记录($0 记录变量)。
  • substr(s, i [, n]) : 从字符串 s 的 i 位置开始,返回最多 n 长度的子字符串,如果省略 n,则返回剩下的全部
  • tolower(str) : 返回将 str 所有字符的小写形式字符串,其与大小写与当前环境有关
  • toupper(str) : 返回将 str 所有字符的大写形式字符串,其与大小写与当前环境有关

2. 算术函数

  • atan2(y, x) : 返回 y/x 的反正切弧度表示
  • cos(expr) : 弧度的余弦
  • exp(expr) : 幂函数
  • int(expr) : 截断至整数的值
  • log(expr) : 自然对数函数
  • rand() : 随机数,值域为 [0, 1)
  • sin(expr) : 弧度的正弦
  • sqrt(expr) : 平方根函数
  • srand([expr]) : 使用 expr 作为种子的随机函数,如果省略 expr 参数,则使用日期中的天。返回值是先前种子

3. 一般函数

  • close( Expression ) 用同一个带字符串值的 Expression 参数来关闭由 print 或 printf 语句打开的或调用 getline 函数打开的文件或管道。如果文件或管道成功关闭,则返回 0;其它情况下返回非零值。如果打算写一个文件,并稍后在同一个程序中读取文件,则 close 语句是必需的。
  • system(command ) 执行 Command 参数指定的命令,并返回退出状态。等同于 system 子例程。
  • Expression | getline [ Variable ] 从来自 Expression 参数指定的命令的输出中通过管道传送的流中读取一个输入记录,并将该记录的值指定给 Variable 参数指定的变量。如果当前未打开将 Expression 参数的值作为其命令名称的流,则创建流。创建的流等同于调用 popen 子例程,此时 Command 参数取 Expression 参数的值且 Mode 参数设置为一个是 r 的值。只要流保留打开且 Expression 参数求得同一个字符串,则对 getline 函数的每次后续调用读取另一个记录。如果未指定 Variable 参数,则 $0 记录变量和 NF 特殊变量设置为从流读取的记录。
  • getline [ Variable ] < Expression 从 Expression 参数指定的文件读取输入的下一个记录,并将 Variable 参数指定的变量设置为该记录的值。只要流保留打开且 Expression 参数对同一个字符串求值,则对 getline 函数的每次后续调用读取另一个记录。如果未指定 Variable 参数,则 $0 记录变量和 NF 特殊变量设置为从流读取的记录。
  • getline [ Variable ] 将 Variable 参数指定的变量设置为从当前输入文件读取的下一个输入记录。如果未指定 Variable 参数,则 $0 记录变量设置为该记录的值,还将设置 NF、NR 和 FNR 特殊变量。