这篇文章上次修改于 410 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

介绍

  • 是一种强大的文本处理工具,通常用于从文本文件或数据流中提取和处理数据

语法

  • awk 'pattern { action }' [file]
  • pattern:用于指定需要匹配的条件,可以是文本字符串或正则表达式。
  • { action }:在匹配到指定 pattern 的行上执行的动作。
  • file:要处理的输入文件名, 不制定文件则使用标准输入

参数

参数 说明
-F<分隔符>--field-separator=<分隔符> 指定字段分隔符。默认是空格。
-f <脚本文件>--file=<脚本文件> 从指定的脚本文件中读取 awk 脚本。
-v <变量名>=<值> awk 脚本中设置变量的值。
-W <关键字>--word-seq=<关键字> 指定字符串字段的分隔符。
-w--posix 使用 POSIX 兼容模式。
-M--bignum 启用大数运算模式。
-b--characters-as-bytes 将字符视为字节。
-c--traditional 使用传统 awk 语法。
-C--copyright 打印版权信息。
-d--debug 打印调试信息。
-D <选项>--gen-pot=<选项> 生成 Gettext 模板。
-e <脚本>--source=<脚本> 直接在命令行中指定 awk 脚本。
-E <命令>--re-interval=<命令> 启用扩展的正则表达式语法。
-g--gen-gettext 生成 Gettext 目录。
-h--help 打印帮助信息。
-l <库>--use-lc-numeric=<库> 使用指定的本地化库。
-L--lint 启用 awk 脚本的语法检查。
-n--non-decimal-data 允许八进制和十六进制的数值。
-N--use-lc-numeric 使用本地化库。
-o <文件>--pretty-print=<文件> 将输出格式化并写入文件。
-O <级别>--optimize=<级别> 设置优化级别。
-p--profile 启用性能分析。
-P <路径>--dump-variables=<路径> 将变量信息写入指定路径的文件。
-r--re-interval 启用扩展的正则表达式语法。
-s--no-optimize 禁用所有优化。
-S--sandbox 启用沙盒模式。
-t--traditional 使用传统 awk 语法。
-V--version 打印版本信息。

请注意,awk的不同版本可能具有不同的参数和功能。上述列表中列举的是一些常见的参数,您可以通过在终端中运行 man awk 命令来查看特定版本的 awk 的完整文档。

内置变量

内置变量 说明
$0 匹配整个输入记录。
$1, $2, ... 匹配输入记录中的第一个、第二个字段,依此类推。
NF 包含当前记录的字段数。
NR 包含当前记录的相对行号。
FNR 包含当前记录的相对行号(针对当前文件)。
FILENAME 包含当前输入文件的名称。
FS 包含字段分隔符,默认为一个空格。
OFS 输出字段分隔符,默认为一个空格。
RS 输入记录分隔符,默认为换行符。
ORS 输出记录分隔符,默认为换行符。
ARGC 包含命令行参数的数量。
ARGV 包含命令行参数的数组。
ENVIRON 包含系统环境变量的数组。
IGNORECASE 如果设置为非零值,则字符串比较不区分大小写。
CONVFMT 控制数字转换为字符串的格式。
OFMT 控制数字输出的格式。
RSTART 匹配函数(如 match())设置的字符串的起始位置。
RLENGTH 匹配函数(如 match())设置的匹配字符串的长度。

执行流程

  1. BEGIN{} : 最开始执行
  2. // : 正则
  3. {} : 循环体
  4. END{} : 最后执行

awk中的函数

print : 打印
printf : 格式化打印
%s : 字符串
%d : 数字
- : 左对齐
+ : 右对齐
15 : 至少占用15字符

比较表达式

> : 小于
< : 大于
>= : 小于等于
<= : 大于等于
~ : 正则匹配(包含)
!~ : 正则匹配(不包含)

逻辑表达式

&& : 逻辑与
|| : 逻辑或
! : 逻辑非

算术表达式

+ :加
- :减
* :乘
/ :除
% :求余

流程控制

  • 流程控制只存在循环之中

if 使用格式:

   if(){}           : 单分支
   if(){}else{}             : 双分支
   if(){}else if(){}else{}    : 多分支

for循环使用格式:

for(i="初始值":条件判断:游标){}

while循环格式

while(条件判断){}

列子

  • 获取/etc/password 文件的第一行到第三号,取行号,第一列,倒数第二列和最后一列
# 使用 —F 制定文件列的分割符 NR==1,NR==3 指定1到3行,使用BEGIN和END增加头尾

[root@236]# awk -F ":" 'BEGIN{print "获取passwd文件部分数据"}NR==1,NR==3{print NR,$1,$(NF-1),$NF}END{printf "%s\n", "数据获取结束"}' /etc/passwd
获取passwd文件部分数据
1 root /root /bin/bash
2 bin /bin /sbin/nologin
3 daemon /sbin /sbin/nologin
数据获取结束

  • 使用| 作为输出分割符

[root@236]# awk -F: 'BEGIN{OFS=" | "}BEGIN{printf "|%+10s|%-15s|\n", "用户解释器","用户名"}NR==1,NR==5{printf "|%+15s|%-15s|\n", $NF, $1}' /etc/passwd | 用户解释器|用户名 | | /bin/bash|root | | /sbin/nologin|bin | | /sbin/nologin|daemon | | /sbin/nologin|adm | | /sbin/nologin|lp |
  • 使用正则表达式定位

[root@AY140330180959236303Z ~]# awk -F ":" '/^root/{print $0}' /etc/passwd root:x:0:0:root:/root:/bin/bash
  • 比较表达式
# 要求打印属组ID大于属主ID的行
[root@236]# awk -F: '$4 > $3{print $0}' /etc/passwd
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

# 打印结尾包含bash字符串的行
# $NF ~ /bash/  :尾部最后一列 包含 bash 的行
# ~        : 包含
[root@236]# awk -F: '$NF ~ /bash/{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash

  • 逻辑表达式
# && 逻辑测试 所有条件必须满足
[root@236]# awk -F: '$3 + $4 > 500 && $3 * $4 > 500{print $0}' /etc/passwd
saslauth:x:499:76:"Saslauthd user":/var/empty/saslauth:/sbin/nologin

#  || 逻辑测试 , 有一个条件是真

[root@236]# awk -F: '$3 + $4 > 2000 || $3 * $4 > 2000{print $0}' /etc/passwd
nobody:x:99:99:Nobody:/:/sbin/nologin

#  ! 逻辑测试 条件取反 

[root@AY140330180959236303Z ~]# awk -F: '!($3 + $4 > 2){print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin

  • 算术加运算
[root@236]# awk -F: '$3 + $4 > 1009{print $0}' /etc/passwd

  • 条件控制和循环

# if条件判断 [root@236]# awk -F: 'NR==1,NR==5{if($3>$4){print "大于"}else{print "小于或等于"}}' /etc/passwd 小于或等于 小于或等于 小于或等于 小于或等于 小于或等于 # for 循环 # 第一行循环打印三次 [root@236]# awk -F: 'NR==1{for(p=0;p<3;p++){print $0}}' /etc/passwd root:x:0:0:root:/root:/bin/bash root:x:0:0:root:/root:/bin/bash root:x:0:0:root:/root:/bin/bash # while 循环 [root@236]# awk -F: 'NR==1{p=0; while(p<2){p++; print $0}}' /etc/passwd root:x:0:0:root:/root:/bin/bash root:x:0:0:root:/root:/bin/bash [root@236]# awk -F: 'NR==1{p=0; while(p<3){print $0,p++}}' /etc/passwd root:x:0:0:root:/root:/bin/bash 0 root:x:0:0:root:/root:/bin/bash 1 root:x:0:0:root:/root:/bin/bash 2
  • 每隔5行,打印一行横线
awk -F: '{if(NR%5==0){print "----------"}print $0}' /etc/passwd