awk 是一个文本处理工具,通常用于处理数据并生成结果报告。其命名源于三位创始人姓氏首字母:Alfred Aho、Peter Weinberger、Brian Kernighan。
语法:
awk [options] 'BEGIN{} pattern {commands} END{}' file
stdout | awk [options] 'BEGIN{} pattern {commands} END{}'
说明:
options
选项
BEGIN{}
正式处理数据之前执行
pattern
匹配模式
{commands;...}
处理命令,可能多行
END{}
处理完所有匹配数据后执行
内置变量
变量名
说明
$0
整行内容
$1-$n
当前行的第 1 - n 个字段(列)
NF
Number Field ,当前行字段个数(多少列)
NR
Number Row ,当前行的行号,从 1 开始计数
FNR
File Number Row ,多文件处理时,每个文件行号单独计数,都是从 0 开始
FS
Field Separator ,输入字段分隔符(默认空格或 tab 键)
RS
Row Separator ,输入行分隔符(默认回车换行)
OFS
Output Field Separator ,输出字段分隔符(默认空格)
ORS
Output Row Separator ,输出行分隔符(默认回车换行)
FILENAME
当前输入的文件名字
ARGC
命令行参数个数
ARGV
命令行参数数组
示例:
1 2 3 4 5 6 7 8 ➜ awk 'BEGIN{FS=":"} {print $1}' /etc/passwd ➜ awk 'BEGIN{FS=":";RS="--"} {print $1,$2}' /etc/passwd ➜ awk 'BEGIN{FS=":"} {print $NF}' /etc/passwd
格式化输出(printf)
格式符
说明
修饰符
说明
%s
字符串
-
左对齐
%d
十进制
+
右对齐
%f
浮点数
#
八进制前面加 0,十六进制前面加 0x
%x
十六进制
%o
八进制
%e
科学计数法
%c
单个字符的 ASCII 码
示例:
1 2 3 4 5 6 7 8 9 10 11 ➜ awk 'BEGIN{FS=":";OFS="-"}{printf "%+20s %20.3f %-20s\n",$1,$3,$7}' /etc/passwd root 0.000 /bin/bash bin 1.000 /sbin/nologin daemon 2.000 /sbin/nologin adm 3.000 /sbin/nologin lp 4.000 /sbin/nologin
模式匹配(pattern)
RegExp
:/patern/
关系运算
:<
、>
、<=
、>=
、==
、!=
、~
正则匹配、!~
非正则匹配、&&
与、||
或、!
非
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ➜ awk 'BEGIN{FS=":"} /^root/ {print $0}' /etc/passwd root:x:0:0:root:/root:/bin/bash ➜ awk 'BEGIN{FS=":"} $3>1000 {print $0}' /etc/passwd nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin ➜ awk 'BEGIN{FS=":"} $7=="/sbin/nologin" {print $0}' /etc/passwd bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin ➜ awk 'BEGIN{FS=":"} $7~/.*nologin$/ {print $0}' /etc/passwd bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin ➜ awk 'BEGIN{FS=":"} $3>500 && $7~/.*nologin$/ {print $0}' /etc/passwd chrony:x:997:995::/var/lib/chrony:/sbin/nologin dockerroot:x:996:993:Docker User:/var/lib/docker:/sbin/nologin
计算表达式 示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ➜ awk 'BEGIN{x=10;y=2; print x+y}' 12 ➜ awk 'BEGIN{x=10;y=2; print x*y}' 20 ➜ awk 'BEGIN{x=10;y=2; print x^y}' 100 ➜ awk 'BEGIN{x=10;y=2; print x**y}' 100 ➜ awk 'BEGIN{x=10;y=x++; print x,y}' 11 10 ➜ awk 'BEGIN{x=10;y=++x; print x,y}' 11 11 ➜ awk 'BEGIN{idx=0;} /^$/ {idx++; print NR} END{print idx;}' /etc/passwd
流程控制语句 语法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 if (condition1) { } else if (condition2) { } else { } while (condition) { } do while (condition)for (i=0;i<10;i++) { }
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ➜ awk 'BEGIN{FS=":"} { if($3<10 && $7="/sbin/nologin") {print "this is if"} else if($3>500) {print "this is else if"} else {print "this is else"}}' /etc/passwd this is if this is if this is else this is else if this is else ➜ awk 'BEGIN{ while(i<10) { sum+=i; i++}; print sum}' 45 ➜ awk 'BEGIN{do { sum+=i; i++; } while(i<10); print sum}' 45 ➜ awk 'BEGIN{ for(i=0;i<10;i++) { sum+=i; }; print sum}' 45
字符串函数
函数名
说明
返回值
length(str)
计算字符串长度
整数长度值
index(str,sub_str)
在 str 中查找 sub_str 的位置
位置索引,从 1 计数
tolower(str)
转小写
转换后的小写字符串
toupper(str)
转大些
转换后的大写字符串
substr(str,start,length)
从 str 第 start 个字符开始,截取 length 位
截取后到子串
split(str,arr,fs)
按 fs 拆分字符串,结果保存到 arr
拆分后子串的个数
match(str,reg)
在 str 中按 reg 查找,返回位置
索引位置
sub(reg,new_sub_str,str)
在 str 中搜索符合 reg 的子串,将其替换为 new_sub_str,只替换第一个
替换的个数
gsub(reg,new_sub_str,str)
类似 sub
,替换所有
替换的个数
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ➜ awk 'BEGIN{FS=":"} { print length($1),toupper($1),substr($1,0,2),sub(/oo/,"11",$1),$1}' /etc/passwd 4 ROOT ro 1 r11t 3 BIN bi 0 bin 6 DAEMON da 0 daemon 4 SYNC sy 0 sync ➜ awk 'BEGIN{str="Shell;Python;C;C++;Java;PHP"; split(str,arr,";"); print arr[2]}' Python ➜ awk 'BEGIN{str="Shell;Python;C;C++;Java;PHP"; split(str,arr,";"); for(i in arr) { print arr[i]; }}' C++ Java PHP Shell Python C
常用选项(options)
-v
参数传递
-f
指定脚本文件
-v
指定分隔符
-V
查看 awk 版本
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 ➜ var1=10 ➜ var2="hello awk" ➜ awk -v var1="$var1 " -v var2="$var2 " 'BEGIN{print var1,var2}' 10 hello awk ➜ touch script.awk BEGIN{ FS=":" } { if ($3 <10 && $7 ="/sbin/nologin" ) { print "this is if" } else if ($3 >500) { print "this is else if" } else { print "this is else" } } ➜ awk -f script.awk /etc/passwd $ awk -F: '{print $1}' pwd root bin daemon
数组 shell 中的数组操作如下:
操作
示例
输出
定义一个数组
arr=("Python" "PHP" "Java" "Go" "Rust")
某个数组元素(下标从 0 开始)
echo ${arr[2]}
Java
数组元素个数
echo ${#arr[@]}
5
某个元素的长度
echo ${#arr[0]}
6
修改元素值
arr[2]="JAVA"
删除数组元素
unset arr[1]
打印所有数组元素)
echo ${arr[@]}
Python JAVA Go Rust
分片访问
echo ${arr[@]:0:2}
Python JAVA
数组元素替换(找到的第一个)
echo ${arr[@]/A/a}
Python JaVA Go Rust
数组元素替换(所有)
echo ${arr[@]//A/a}
Python JaVa Go Rust
数组遍历
for a in ${arr[*]}; do echo $a; done
而 awk 中数组的使用略有不同,它使用关联数组 提供数组功能,即数组的索引可以是数字 或任意字符串 。
语法示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 ➜ awk 'BEGIN{arr[0]=0; arr["second"]="2"; print arr[0],arr["second"];}' 0 2 ➜ awk 'BEGIN{arr[0]=0; arr["second"]="2"; print arr[0]+3,arr["second"];}' 3 2 ➜ awk 'BEGIN{arr[0]=0;arr["second"]="2"; delete arr["second"]; print arr["second"];}' ➜ awk 'BEGIN{str="Python Rust PHP Go"; arrLen=split(str,arr," "); for(i in arr){ print i,arr[i] }}' 4 Go 1 Python 2 Rust 3 PHP ➜ awk 'BEGIN{str="Python Rust PHP Go"; arrLen=split(str,arr," "); for(i=1;i<=arrLen;i++){ print i,arr[i] }}' 1 Rust 2 Go 3 Python 4 PHP