前言
被称为 Linux 文本操作三剑客之一的 awk 不但可以处理复杂文件输出,更是一门编程语言。支持对文本每行每列精确读出、格式化输出、正则匹配、if 判断、数组、循环。
目录
1. 语法
awk [参数选项] [条件筛选] 文件名
1.1. 选项参数
-F:指定分隔符
-v:设置变量
-f:从脚本文件中读取awk命令
1.2. 内置变量
$n :n用数字代替,表示匹配第n列
$0 :匹配全部列
NR :输出每行行号
NF :输出每行字段数
$NF:输出最后一列
$(NF - 1):输出倒数第二列
1.3. 运算符
**************** 逻辑类 ****************
&&:逻辑匹配-与
||:逻辑匹配-或
! :逻辑匹配-非
~ :匹配正则表达式
!~:正则表达式取反
**************** 运算类 ****************
+ :加
- :减
* :乘
/ :除
% :取余
^ :幂
> :大于
< :小于
==:等于
!=:不等于
>=:大于等于
<=:小于等于
2. 参数示例
2.1. 示例选项参数:-F
awk -F '|' '{print $1}' file.txt
awk -F '2' '{print $1}' file.txt
awk -F '[|,:]' file # 指定多个分隔符
2.2. 示例选项参数:-v
awk -v 'num=1' '{print $1 + num}' file.txt
a=10
awk -v "b=$a" 'BEGIN{print b}'
2.3. 示例选项参数:-f
3. 常见用法
3.1. 匹配行
3.1.1. 匹配第1行
awk 'NR == 1' file.txt # NR等于1匹配第一行,等于2匹配第二行
3.1.2. 匹配最后1行
awk 'END{print $0}' file.txt
3.1.3. 匹配大于第1行的全部行
awk '$NR > 1' file.txt # 使用运算符,>、<、= 皆可通用
3.1.4. 匹配6-8行
awk 'NR>=6 && NR<=8' file.txt # 使用逻辑符进行匹配
3.1.5. 输出匹配行的下1行
seq 1 10 |awk '/3/ {getline; print}'
输出匹配行 + 下1行
seq 1 10 |awk '/3/ {print; getline; print}'
3.1.6. 打印行号
awk '{print NR}' file.txt # 只打印行号
awk '{print NR, $0}' file.txt # 输出所有列,并在最前面输出行号
awk 'END{print NR}' file.txt # 输出最后一行的行号,可以理解为总行数
3.1.7. 模糊匹配行
seq 1 10 |awk '/3/ {print $0}' # 匹配包含3的行
3.1.8. 范围匹配字符串
使用逗号分割,/b/ 表示开始行,/d/表示结束行,取中间范围
echo -e " a \n b \n c \n d" |awk '/b/, /d/'
3.1.9. 逻辑匹配
&& 匹配,匹配包含a且包含b的行
echo -e "abc \n def" |awk '/a/ && /b/ {print $0}'
|| 匹配,匹配包含a或者包含e的行
echo -e "abc \n def" |awk '/a/ || /e/ {print $0}'
!取反,不匹配包含a的行
echo -e "abc \n def" |awk '! /a/ {print $0}'
3.1.10. 忽略大小写
IGNORECASE=1 表示忽略大小写
echo -e " a \n A \n b \n c" |awk 'BEGIN{IGNORECASE=1} /a/'
3.2. 匹配列
3.2.1. 匹配第一列
awk '{print $1}' file.txt # $0匹配全部列,$1匹配第一列,$2匹配第二列
3.2.2. 匹配最后一列
awk '{print $NF}' file.txt
不匹配最后一列
echo "a b c d" |awk '{$NF=""; print $0}'
3.2.3. 匹配倒数第二列
awk '{print $(NF - 1)}' file.txt # NF - 1 表示倒数第二列,NF - 2 表示倒数第三列
不匹配倒数第2列
echo "a b c d" |awk '{$(NF-1)=""; print $0}'
不匹配倒数第2列和最后1列
echo "a b c d" |awk '{$NF=""; $(NF-1)=""; print $0}'
3.2.4. 匹配第2列和第5列
awk '{print $2, $5}' file.txt # 指定匹配多少列,增加 $n 即可
awk '{print $2 $5}' file.txt # 去除逗号,表示去除分割输出第2列和第5列
3.2.5. 匹配第3列到第五列
awk '{for (i=3; i<=5; i++) print $i}' file.txt # 匹配第3列到第5列
awk '{for (i=3; i<=NF; i++) print $i}' file.txt # 匹配第3列到最后一列(纵向输出)
awk '{for (i=3; i<=NF; i++) {printf "%s ", $i}}' file.txt # 横向输出
3.2.6. 精确匹配某一列
awk '/^a/' file.txt # 匹配以 a 开头的列
awk '/c$/' file.txt # 匹配以 c 结尾的列
awk '$1 == "a"' file.txt # 匹配第1列等于 a 的行,$1 表示第一列,那么$2等于第二列
3.2.7. 模糊匹配某一列
awk '$1 ~ "a"' file.txt # 匹配第一列存在 a 的行,$1等于第一列,那么$2等于第2列
匹配第1列包含a或b
awk '$1 ~ /[ab]/ file.txt
匹配第1列不包含a或b
awk '$1 !~ /[ab]/ file.txt
3.3. BEGIN / END使用
- BEGIN:在处理文件之前执行该操作
- END:在处理文件之后执行该操作
3.3.1. 开始前输出字符串
seq 1 3 |awk 'BEGIN{print "--- start ---"} {print $0}'
3.3.2. 结束后输出字符串
seq 1 3 |awk '{print $0} END{print "--- stop ---"}'
4. 正则表达式
字符 | 解释 | 用法 |
^ | 匹配以什么开始 | awk '/^ab/p' 匹配以ab开头的行 |
$ | 匹配以什么结尾 | awk '/ab$/p' 匹配以ab结尾的行 |
. | 匹配任意一个字符 | awk '/a.c/p' 只匹配a与c之间拥有一个字符的行 |
.+ | 匹配1次或多次 | awk '/a.+c/p' 匹配a与c之间任意字符的行,不包含ac |
* | 匹配0次或多次 | awk '/a*c/p' 匹配a与c之间任意字符的行,包含ac |
| | 相当于 or | awk '/ab|ac/p' 匹配包含ab或ac的行 |
[] | 匹配括号中任意一个字符 | awk '/[ac]/p' 匹配包含a或c的行 |
[^] | 匹配非括号中任意一个字符 | awk '/[^ac]/p' 匹配不包含a或c的行 |
- | [0-9] 匹配数字 | awk '/[0-9]/p' 匹配包含数字的行 |
[^0-9] 匹配非数字 | awk '/[^0-9]/p' 匹配不包含数字的行 | |
[a-z] 匹配小写字符串 | awk '/[a-z]/p' 匹配包含小写字符串的行 | |
[^a-z] 匹配非小写字符串 | awk '/[^a-z]/p' 匹配不包含小写字符串的行 | |
[A-Z] 匹配大写字符串 | awk '/[A-Z]/p' 匹配包含大写字符串的行 | |
[^A-Z] 匹配非大写字符串 | awk '/[^A-Z]/p' 匹配不包含大写字符串的行 | |
() | (a|b) 匹配括号中任意字符 | awk '/0(a|b)1/p' 只匹配0a1和0b1的行 |
(a)+ 匹配包含1个或多个a | awk '/0(a)+1/p' 匹配0和1之前1个或多个a,0a1、0aa1... | |
{} | {n} 指定匹配n个以上 | awk '/ab{2}/p' 匹配包含ab,且a或b连续为2次以上:abb |
{n,m} 指定匹配 n-m 个 | awk '/ab{2,3}/p' 匹配包含ab,且a或b连续为2-3次:abb、aaab |
5. 数学运算
第一列加2
seq 1 10 |awk '{print $1 + 2}'
第一列减2
seq 1 10 |awk '{print $1 - 2}'
第一列乘以2
seq 1 10 |awk '{print $1 * 2}'
第一列除以2 (支持浮点数)
seq 1 10 |awk '{print $1 / 2}'
第一列除以2取余
seq 1 10 |awk '{print $1 % 2}'
第一列2次幂
seq 1 10 |awk '{print $1 ^ 2}'
三目运算
seq 1 3 |awk '{print $0==2 ? "是2" : "不是2"}'
求所有数之和
seq 1 10 |awk '{sum += $1} END{print sum}' # 结果55
求最大值
seq 1 10 |awk 'BEGIN{max = 0} {if ($1+0 > max+0) max=$1} END{print max}'
求最小值
seq 1 10 |awk 'BEGIN{min = 65536} {if ($1+0 < min+0) min=$1} END{print min}'
求平均值
seq 1 10 |awk '{sum += $1} END{print sum/NR}'
6. IF判断
匹配第1列大于1,且最后一列等于9的行
awk '{if($1 > 0 && $NF == 9) print $0}' file.txt
匹配第1列大于1或最后1列等于8的行
awk '{if($1 > 0 || $NF == 8) print $0}' file.txt
判断第1列等于3
seq 5 |awk '{if ($1 == "3") print $0}'
包含3的行输出yes,否则输出no
seq 5 |awk '{if ($0 == "3") print "yes"; else print "no"}'
多分支
seq 1 10 |awk '{
if($1==4)
{print "yes"}
else
if($1==6)
{print "yes"}
else
if($1==9)
{print "yes"}
else
{print "no"}}'
7. 循环语句
7.1. while 循环
循环 1-10
awk 'BEGIN{ i=1; while(i <= 10) {print i; i++}}'
循环 1-10,且每个数字后面添加 aaa 字样
awk 'BEGIN{ i=1; while(i <= 10) {print i "aaa"; i++}}'
定义变量 a=abcd,循环10次 abcd
awk -v 'a=abcd' 'BEGIN{ i=1; while(i <= 10) {print a; i++}}'
7.2. for 循环
遍历1-10
awk 'BEGIN{for (i=1; i<=10; i++) print i}'
打印10次abc
awk 'BEGIN{for (i=1; i<=10; i++) print "abc"}'
7.3. 跳出循环
跳出整个循环 break
awk 'BEGIN{ for(i=1; i<=10; i++) {if (i==3) break; print i}}'
跳出当前循环 continue
awk 'BEGIN{ for(i=1; i<=10; i++) {if (i==3) continue; print i}}'
8. awk 内置函数
8.1. 生成随机数
使用awk内置函数:rand() 和 srand()
生成随机数 0-1
awk 'BEGIN{srand(); print rand()}'
生成随机数 1-100(int表示转换为整数)
awk 'BEGIN{srand(); print int(rand() * 100)}'
生成随机数 1w-10w
awk 'BEGIN{srand(); num=int(rand() * 100000); if(num < 10000) (num += 10000); print num}'
8.2. 时间戳转换
输出当前时间戳
awk 'BEGIN{print systime()}'
转换时间戳为日期时间格式
echo "1662973166" |awk '{print strftime("%Y-%m-%d %H:%M:%S",$0)}'
8.3. 文件比较
获取两个文件相同部分
awk 'FNR==NR{a[$0];next}{if($0 in a)print $0}' file1 file2
找出不包含file1内容的file2内容
awk 'FNR==NR{a[$0];next}!($0 in a)' file1 file2
找出不包含file2内容的file1内容
awk 'FNR==NR{a[$0];next}!($0 in a)' file2 file1
9. 文本三剑客其他命令
本文含有隐藏内容,请 开通VIP 后查看