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{}
解决完所有匹配数据后执行
<!-- more -->
内置变量
变量名 | 阐明 |
---|---|
$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 列➜ awk 'BEGIN{FS=":"} {print $1}' /etc/passwd# 以 -- 分隔成行,以 : 分隔成列,输入第 1、2 列➜ awk 'BEGIN{FS=":";RS="--"} {print $1,$2}' /etc/passwd# 以 : 分隔列,输入最初一列,因为 NF 变量是总列数➜ awk 'BEGIN{FS=":"} {print $NF}' /etc/passwd
格式化输入(printf)
格局符 | 阐明 | 修饰符 | 阐明 |
---|---|---|---|
%s | 字符串 | - | 左对齐 |
%d | 十进制 | + | 右对齐 |
%f | 浮点数 | # | 八进制后面加 0,十六进制后面加 0x |
%x | 十六进制 | ||
%o | 八进制 | ||
%e | 迷信计数法 | ||
%c | 单个字符的 ASCII 码 |
示例:
# printf "%+20s %-20s\n",$1,$7# - 左对齐;+ 右对齐# 20 列宽,有余则补空# s 打印字符串# .3f 打印保留 3 位数的浮点数➜ 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/
关系运算
:<
、>
、<=
、>=
、==
、!=
、~
正则匹配、!~
非正则匹配、&&
与、||
或、!
非
示例:
# 打印以 root 结尾的行➜ awk 'BEGIN{FS=":"} /^root/ {print $0}' /etc/passwdroot:x:0:0:root:/root:/bin/bash# 打印第 3 列大于 1000 的行➜ awk 'BEGIN{FS=":"} $3>1000 {print $0}' /etc/passwdnfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin# 打印第 7 列是 /sbin/nologin 的行➜ awk 'BEGIN{FS=":"} $7=="/sbin/nologin" {print $0}' /etc/passwdbin:x:1:1:bin:/bin:/sbin/nologindaemon:x:2:2:daemon:/sbin:/sbin/nologin# 打印第 7 列以 nologin 结尾的行➜ awk 'BEGIN{FS=":"} $7~/.*nologin$/ {print $0}' /etc/passwdbin:x:1:1:bin:/bin:/sbin/nologindaemon:x:2:2:daemon:/sbin:/sbin/nologin# 打印第 3 列大于 500,并且第 7 列以 nologin 结尾的行➜ awk 'BEGIN{FS=":"} $3>500 && $7~/.*nologin$/ {print $0}' /etc/passwdchrony:x:997:995::/var/lib/chrony:/sbin/nologindockerroot:x:996:993:Docker User:/var/lib/docker:/sbin/nologin
计算表达式
示例:
# 数学计算➜ 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
流程管制语句
语法:
# 条件判断if(condition1) { # do something} else if(condition2) { # do something} else { # do something}# 循环while(condition) { #do something}do # do somethingwhile(condition)for(i=0;i<10;i++) { # do something}
示例:
# 如果第 3 列小于 10 并且第 7 列是 /sbin/nologin 的行打印 this is if# 如果第 3 列大于 500 的打印 this is else if# 否则打印 this is else➜ 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/passwdthis is ifthis is ifthis is elsethis is else ifthis is else# 计算 1-10 相加的后果# 留神:变量不须要提前申明➜ 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 ,替换所有 | 替换的个数 |
示例:
# sub(/oo/,"11",$1) 返回替换的个数;前面的 $1 为替换后的值➜ awk 'BEGIN{FS=":"} { print length($1),toupper($1),substr($1,0,2),sub(/oo/,"11",$1),$1}' /etc/passwd4 ROOT ro 1 r11t3 BIN bi 0 bin6 DAEMON da 0 daemon4 SYNC sy 0 sync# 数组下标从 1 开始➜ 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++JavaPHPShellPythonC
罕用选项(options)
-v
参数传递-f
指定脚本文件-v
指定分隔符-V
查看 awk 版本
示例:
# 引入内部变量➜ var1=10➜ var2="hello awk"➜ awk -v var1="$var1" -v var2="$var2" 'BEGIN{print var1,var2}'10 hello awk# 把所有操作抽离到一个独立文件# 倡议:简单操作优先应用这种形式,更易于程序了解和治理➜ touch script.awkBEGIN{ 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# -F: 相当于 BEGIN{FS=":"}$ awk -F: '{print $1}' pwdrootbindaemon
数组
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 中数组的应用略有不同,它应用关联数组提供数组性能,即数组的索引能够是数字或任意字符串。
语法示例:
# 定义# 语法:array_name[index]=value➜ 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# 删除数组元素# 语法:delete array_name[index]➜ awk 'BEGIN{arr[0]=0;arr["second"]="2"; delete arr["second"]; print arr["second"];}'# 遍历数组# 形式一:for ... in 是无序输入➜ awk 'BEGIN{str="Python Rust PHP Go"; arrLen=split(str,arr," "); for(i in arr){ print i,arr[i] }}'4 Go1 Python2 Rust3 PHP# 形式二:for(i=1;i<=len;i++) { ... } 有序输入➜ awk 'BEGIN{str="Python Rust PHP Go"; arrLen=split(str,arr," "); for(i=1;i<=arrLen;i++){ print i,arr[i] }}'1 Rust2 Go3 Python4 PHP