简介
awk 命令利用一组用户提供的指令来将一组文件与用户提供的扩展正则表达式比较,一次一行。然后在任何与扩展正则表达式匹配的行上执行操作。
awk 命令的模式搜索比 grep 命令的搜索更常用,且它允许用户在输入文本行上执行多个操作。awk 命令编程语言不需要编译,并允许用户使用变量、数字函数、字符串函数和逻辑运算符。
语法
awk [OPTIONS] -f program_file [--] filename_list
awk [OPTIONS] [--] program filename_list
输出语句
语法:
print [ ExpressionList ] [ Redirection ] [ Expression ]
ExpressionList 参数指定的每个表达式的值写至标准输出。
Redirection 参数重定向输出,此参数可指定使用 >(大于号)、>>(双大于号)和 |(管道)进行的三种输出重定向。
Expression 参数是文件的路径名称
[root@n1 ~]# cat 1.txt
smiley, allen
smith, alan
smithern, harry
smithhern, anne
smitters, alexis
[root@n1 ~]# awk -F "," '{print $1}'
[root@n1 ~]# awk -F "," '{print $1}' < 1.txt > 2.txt
[root@n1 ~]# awk -F "," '{print $1}' < 1.txt | echo 1
printf
语法:
printf Format [ , ExpressionList ] [ Redirection ] [ Expression ]
printf 语句将 ExpressionList 参数指定的表达式以 Format 参数指定的格式写至标准输出。除了 c 转换规范(%c)不同外,printf 语句和 printf 命令起完全相同的作用。Redirection 和 Expression 参数与在 print 语句中起相同的作用。
[root@n1 ~]# awk -F "," '{printf("type:%s\tname:%s\n",$1,$2)}' < 1.txt
- 格式符:
- %d,%i:十进制整数;
- %f:显示浮点数;
- %s:显示字符串;
- %u:无符号整数;
- %%:显示%自身。
- 修饰符:
- N:显示宽度;N为数值,宽度不足时若为左对齐则右边空格补足,若右对齐则左边空格补足。
- -:左对齐;
- +:显示数值正负号。
- 0:表示以0填充。
特殊变量
ARGV:命令行参数数组。从0开始计数直到ARGC-1。
ARGC:ARGV数组元素的个数。
FILENAME:当前处理的文件名。
FNR:当前处理文件的记录号。(file record num)
NR:已处理的总记录数。多个文件时不重置。(record num)
NF:当前记录的字段总数。(field num)
FS:输入的字段分隔符。默认为空白。(file separate)
OFS:输出的字段分隔符。默认为空白。(output record separate)
RS:输入流的记录分隔符。默认为"\n"。(record separate)
ORS:输出流的记录分隔符。默认为"\n"。(output record separate)
OFMT:printf输出数值转换成字符串输出时的格式。默认为"%.6g"。
CONVFMT:printf输出数值转换成字符串输出时的格式。会被OFMT覆盖。默认为"%.6g"。
RLENGTH:被match函数匹配的字符串的长度。
RSTART:被match函数匹配的字符串的开始位置。
SUBSEP:下标分隔符。默认为"\034",ASCII中034代表的是双引号'"'
关系表达式
关系运算符 <(小于)、>(大于)、<=(小于或等于)、>=(大于或等于)、= =(等于)和 ! =(不等于)可用来形成模式。
识别转义序列转义序列
转义序列 含义
\" \"(双引号)标记
\/ /(斜杠)字符
\ddd 其编码由 1、2 或 3 位八进制整数表示的字符,其中 d表示一个八进制数位
\\ \ ( 反斜杠 ) 字符
\a 警告字符
\b 退格字符
\f 换页字符
\n 换行符(请参阅以下的注)
\r 回车字符
\t 跳格字符
\v 垂直跳格
正则表达式
[root@n1 ~]# cat file3
smiley, allen
smith, alan
smithern, harry
smithhern, anne
smitters, alexis
字符 | 功能 | 示例 |
+ | 匹配一个或多个前导字符 | [root@n1 ~]# awk '/smith+ern/' file3 smithern, harry smithhern, anne[root@n1 ~]# awk '/smith+ern/' file3 smithern, harry smithhern, anne |
? | 匹配 0 个或 1 个前导字符 | [root@n1 ~]# awk '/smith?/' file3 smith, alan smithern, harry smithhern, anne smitters, alexis[root@n1 ~]# awk '/smith?/' file3 smith, alan smithern, harry smithhern, anne smitters, alexis |
| | 或 | [root@n1 ~]# awk '/alan|allen/' file3 smiley, allen smith, alan |
( ) | 组合字符串 | [root@n1 ~]# awk '/a(ll)?(nn)?e/' file3 smiley, allen smithhern, anne |
x{m} | x重复m次 | [root@n1 ~]# awk '/h{2}/' file3 smithhern, anne |
x{m,} | x重复至少m次 | [root@n1 ~]# awk '/h{1,}/' file3 smith, alan smithern, harry smithhern, anne |
x{m, n} | x重复至少m次,但不超过n次 | [root@n1 ~]# awk '/h{1,2}/' file3 smith, alan smithern, harry smithhern, anne |
[String] | 指定正则表达式与方括号内 String 变量指定的任何字符匹配 | [root@n1 ~]# awk '/smi[a-l]/' file3 smiley, allen |
[^ String] | 内容与string变量不进行匹配 | [root@n1 ~]# awk '/smi[^a-l]/' file3 smith, alan smithern, harry smithhern, anne smitters, alexis |
~,!~ | 表示指定变量与正则表达式匹配或不匹配 | [root@n1 ~]# awk '$1 ~ /n/' file3(匹配第一个字段有n的) smithern, harry smithhern, anne |
^ | 行首定位符 | [root@n1 ~]# awk '$2 ~/^h/' file3 smithern, harry |
$ | 行尾定位符 | [root@n1 ~]# awk '$2 ~/s$/' file3 smitters, alexis |
. | 匹配任意单个字符 | [root@n1 ~]# awk '/a..e/' file3 smiley, allen smithhern, anne |
* | 匹配 0 个或多个前导字符(包括回车) | [root@n1 ~]# awk '/a.*e/' file3 smiley, allen smithhern, anne smitters, alexis |
\ | 转义字符 | /a\/\// ,匹配a// |
BEGIN 和 END 模式
用 BEGIN 模式指定的操作在读取任何输入之前执行。用 END 模式指定的操作在读取了所有输入后执行
语法:
BGEIN{ACTIONS}PATTERN{ACTIONS}END{ACTIONS}
[root@n1 ~]# cat file1
1 zhang
2 qiao
3 wang
4 li
用BEGIN输出头部内容,END总结行数
[root@n1 ~]# awk -F "," 'BEGIN{print "type name"}{print $1 $2}END{print "total:" NR}' < file1
type name
1 zhang
2 qiao
3 wang
4 li
total:4
数组
awk的数组和shell的数组类似,都支持数值index的普通数组和字符串index的关联数组,其实数值index仍然会转换成字符串格式的index,所以awk的数组类型都是关联数组。
格式:array_name[index]
赋值:array_name[1]=zhang
引用:array_name[1]
删除数组:delete array_name
delete array_name[1]
如果index是字符串,需要用双引号,否则会被当成变量
流程控制语句
条件判断语句
if (expression) statements
if (expression) statements else statements
[root@n1 ~]# cat file2
1 2 3 4
[root@n1 ~]# awk '{if ($1 < $2)print $2 " is big"}' file2
2 is big
while循环
while (expression) statements
[root@n1 ~]# awk '{i=1;while(i<=NF){print NF,$i;i++}}' file2
4 1
4 2
4 3
4 4
do循环
do statements while (expression)
[root@n1 ~]# awk '{i=1;do{print NF,$i;i++;}while(i<=NF)}' file2
4 1
4 2
4 3
4 4
for循环
for (expression; expression; expression) statements
for (expression in array) statements
[root@n1 ~]# awk '{for (i=1;i<=NF;i++){if($i == 4){ print $i "over"; }else{print $i;}}}' file2
1
2
3
4over
遍历数组
[root@n1 ~]# awk 'BEGIN{arr[1]="zhang";arr[2]="li";for(i in arr){print arr[i]}}'
zhang
li
影响循环的动作
break:退出循环。
continue:退出当前循环,进入下一个循环
next:读入下一行,并awk程序的顶端从头开始。这个awk程序是PATTERN{action}这部分,不包括BEGIN{action}。
exit code:直接进入END,若本就在END中,则直接退出awk。如果END中的exit没有定义code,则采用前一个exit的code。
内置函数
awk 命令语言使用算术函数、字符串函数和一般函数。如果打算编写一个文件,且稍后在同一个程序里读取它,那么 close 子例程语句是必需的。
算术函数
- atan2( y, x ) 返回 y/x 的反正切。
- cos( x ) 返回 x 的余弦;x 是弧度。
- sin( x ) 返回 x 的正弦;x 是弧度。
- exp( x ) 返回 x 的指数函数。
- log( x ) 返回 x 的自然对数。
- sqrt( x ) 返回 x 平方根。
- int( x ) 返回 x 的截断至整数的值。
- rand( ) 返回任意数字 n,其中 0 <= n < 1。
- srand( [Expr] ) 将 rand 函数的种子值设置为 Expr 参数的值,或如果省略 Expr 参数则使用某天的时间。返回先前的种子值。
字符串函数
- index(str1,str2):返回子串str2在字符串str1中第一次出现的位置。如果没有指定str1,则返回0。
- length(str1):返回字符串str1的长度。如果未给定str1,则表示计算"$0"的长度。
- substr(str1,p):返回str1中从p位置开始的后缀字符串。
- substr(str1,p,n):返回str1中从p位置开始,长度为n的子串。
- sub(regexp,rep,str2):将str2中第一个被regexp匹配的字符串替换成rep,替换成功则返回1(表示替换了1次),否则返回0。注意是贪婪匹配。
- sub(regexp,rep):将"$0"中第一个被regexp匹配的字符串替换成rep,替换成功则返回1,否则返回0。注意是贪婪匹配。
- gsub(regexp,rep,str2):将str2中所有被regexp匹配的内容替换成rep,并返回替换的次数。
- gsub(regexp,rep):将"$0"中所有被regexp匹配的内容替换成rep,并返回替换的次数。
- match(str1,regexp):如果regexp能匹配str1,则返回匹配起始位置。否则返回0。它会设置内置变量RSTART和RLENGTH的值。
- split(str1,array,sep):使用字段分隔符sep将str1分割到数组array中,并返回数组的元素个数。如果未指定sep则采用FS的值。因此该函数用于切分字段到数组中,下标从1开始。
- sprintf(fmt,expr):根据printf的格式fmt,返回格式化后的expr。
- toupper(str):将str转换成大写字母,并返回新串。
- tolower(str):将str转换成小写字母,并返回新串。
#index、length、toupper、match、substr
[root@n1 ~]# awk 'BEGIN{
print index("realxwxw","xw")
print length("realxwxw")
print toupper("realxwxw")
print match("realxwxw","xw.*")
print substr("realxwxw",7)
}'
5
8
REALXWXW
5
xw
#split
[root@n1 ~]# awk 'BEGIN{
> name="zhang:li:qiao:wang"
> split(name,array,":")
> for(i in array){
> print array[i]}
> }'
wang
zhang
li
qiao
#sprintf
[root@n1 ~]# awk 'BEGIN{
name="zhang:li:qiao:wang"
split(name,array,":")
for(i in array){
print sprintf("name:%s",array[i])}
}'
name:wang
name:zhang
name:li
name:qiao
#sub
[root@n1 ~]# awk 'BEGIN{
name="zhang:li:qiao:wang"
print sub(/q.*o/,"xxx",name)
print name}'
1
zhang:li:xxx:wang
#gsub
[root@n1 ~]# awk 'BEGIN{
str1="realxwxwxw"
print gsub(/xw/,"qq",str1)
print str1}'
3
realqqqqqq
自定义函数
function name ( parameter, parameter, parameter, ... ) {
statements
return expression
}
示例:
计算x+y
[root@n1 ~]# awk 'function sum(x,y){ z=x+y;return z;}BEGIN{print sum(1,2)}'
3
getline函数
getline从标准输入、管道或者当前正在处理的文件之外的其他输入文件获得输入。它负责从输入获得下一行的内容,并给NF,NR和FNR等内建变量赋值。如果得到一条记录,getline函数返回1,如果到达文件的末尾就返回0,如果出现错误,例如打开文件失败,就返回-1。
示例:
执行date,通过管道符输出给getline,并赋值给d,在输出d
[root@n1 ~]# awk 'BEGIN{"date" | getline d;print d}'
Sun Apr 14 11:15:53 CST 2019
打印ls
[root@n1 ~]# awk 'BEGIN{while ("ls" |getline > 0){print}}'
1.txt
2.txt
anaconda-ks.cfg
file1
file2
file3
test_sh
统计/etc/passwd中的行数
[root@n1 ~]# awk 'BEGIN{while (getline < "/etc/passwd" > 0) {l++} print l}'
32
向awk传递变量
通过-v传递
[root@n1 ~]# awk -v name="zhang" 'BEGIN{print name}'
zhang
通过参数数组ARGV
[root@n1 ~]# awk -F "\t" 'BEGIN{
for(i=0;i<ARGC;i++){
print "ARGV["i"]:" ARGV[i]
}
print "ARGC:" ARGC
}' "a" "b"
ARGV[0]:awk
ARGV[1]:a
ARGV[2]:b
ARGC:3
#ARGV[0]存储的是awk命令
给变量加"''"(双引号,单引号)
[root@n1 ~]# name=qiao
[root@n1 ~]# awk 'BEGIN{print "'$name'"}'
qiao
实战
1.匹配/etc/passwd中有root的行
awk -F”:” ‘/root/‘ /etc/passwd
2.统计/etc/passwd的账户人数
awk ‘{count++}END{print “user count is”,count}’ /etc/passwd
3.计算某个文件夹下的文件大小
ls -l | awk ‘BEGIN{size=0;}{size=size+$5}END{print “size is”,size}’
4.统计某个文件夹下的文件占用的字节数,过滤5075892大小的文件
ls -l | awk ‘BEGIN{size=0;print “[start]size:”,size} {if($5!=5075892){size=size+$5;}}END{print “[end]size:”,size}’
5.将文件中有li的行输出
awk ‘/li/ {print $0}’ t.txt
6.输出文件中每行字符超过10的记录
awk ‘length($0) > 10’ 1.txt
7.输出1-7
awk ‘BEGIN { for (i = 1; i <= 7; i++) print i }’
8.输出偶数行的记录
awk ‘NR%2==0’ data
9.指定脚本执行
cat test.awk
#!/bin/bash
BEGIN{print n1,n2}
awk -f test.awk -v n1=”hello” -v n2=”yuehuan”
11.在test2.awk中调用test1.awk中的内容
[root@t1 ~]# cat test1.awk
#!/bin/bash
BEGIN{print "this is test1.awk"}
[root@t1 ~]# cat test2.awk
@include “test1.awk”
BEGIN{print “this is test2.awk” }
[root@t1 ~]# awk -f test2.awk
this is test1.awk
this is test2.awk
12.输出记录中有J的所有域
awk ‘{if($1 ~ /J/)print $0}’ data
13.输出/etc/passwd第三域大于100的记录
awk -F”:” ‘$3>100’ /etc/passwd
14.打印行号小于15,并且最后一域匹配bash的信息
awk -F”:” ‘{if($NR<15 && $NF~/bash/)print $0}’ /etc/passwd
15.打印/etc/passwd中第一域为centos的最后一域
awk -F”:” ‘{if($1~/centos/)print $NF}’ /etc/passwd
16.设当用户ID小于500时,输出系统用户,大于500时,输出普通用户
awk -F: ‘{usertype=$3<500?”系统用户”:”普通用户”;print $1,usertype}’ /etc/passwd
17.将多行1-9的数字打印为3个数字一行
awk ‘ORS=NR%3?” “:”\n”‘ 1.txt
三目运算,取余为0,则输出\n,否则输出空格
参考:
https://www.cnblogs.com/f-ck-need-u/p/7509812.html#5-
https://www.cnblogs.com/losbyday/p/5854707.html
https://www.ibm.com/support/knowledgecenter/zh/ssw_aix_72/com.ibm.aix.cmds1/awk.htm#awk__a171c1266