命令 seq argv pat 基本 line 功能 print 默认
awk 是一门编程语言,它支持条件判断,数组,循环等功能.所以,我们也可以把 awk 理解成一个脚本语言解释器.
grep ,sed,awk被称为linux中的"三剑客".
这三个"剑客"各有特长.
grep 适合单纯的查找或匹配文本
sed 适合编辑匹配到的文本
awk 适合格式化文本,对文本进行较复杂格式处理.报告生成器,格式化文本输出.
AWK 处理流程
我们现在在 linux 的所使用的 awk 其实是 gawk,也就是 GNU awk,简称为 gawk.在系统内使用 awk 和 gawk 其实是一样的
基本用法:
#ll /bin/awk
lrwxrwxrwx. 1 root root 4 Dec 13 20:15 /bin/awk -> gawk
awk [options] 'program' var=value file...
其中 program 通常是被单引号引中.
awk 程序通常由:BEGIN 语句块,program, END 语句块,共 3 部分组成
awk[options] - f programfile
var = value file...awk[options]'BEGIN{ action;... } pattern{ action;... } END{ action;... }'file...
program 又可以细分成 pattern 和 action
? pattern 决定动作语句何时触发及触发事件
比如说可以使用正则表达式,总之就是读取进来数据会满足指定条件
? action 对满足指定条件数据进行处理,放在{}内指明
常用的2个动作就是打印到屏幕咯 print, printf.如果没有指定action动作,默认的动作就是 print $0
记录,域和分割符
记录
文件的每一行称为记录,一般情况下,换行就为一条记录,
这里就是1行记录
#cat file
line1-1:2:3@a:b:c:d@E:F:G
#awk '{print $0}' file
line1-1:2:3@a:b:c:d@E:F:G
如果以@作为记录的分隔符,那么这一行数据里其实就是3行记录
域
#awk 'BEGIN{RS="@"}{print $0}' awk
line1-1:2:3
a:b:c:d
E:F:G
由分隔符分隔的字段, 对于每个域标记为记 $1,$2..$n 称为域标识.$0 为所有域,也就是整条记录.不要跟 shell 中的 $0 混淆.
也可以把域理解为列,字段
域分隔符变量:FS(field sign)
$0 表示显示整行 ,$NF表示当前记录分割后的最后一个域($0和$NF均为内置变量)
$NF表示最后一个字段,NF表示当前记录被分隔符切开以后,一共有几个字段.
假如一条记录被分成了4列,那么NF的值就是4,$NF的值就是$4, 而$4表示当前记录的第4个字段,也就是最后一列.那么每条记录的倒数第二个字段可以写为$(NF-1).注意括号.
分隔符
输入记录分隔符 RS
默认:换行符
输出记录分隔符 ORS
#awk -v RS="@" '{print $0}' file
a b c d
a b c d
---------------------------------------------
默认:换行(\n)
#awk -v ORS="行分隔" '{print $0}' awk
line1-1:2:3@a:b:c:d@E:F:G行分隔line2-1:2:3@a:b:c:d@E:F:G行分隔
---------------------------------------------
字段分隔符 FS
默认:单个空格
使用使用2种格式:
输出字段分隔符 OFS
#awk -F "@" '{print $2,$3}' file
a:b:c:d E:F:G
#awk -v FS="@" '{print $2,$3}' file
a:b:c:d E:F:G
---------------------------------------------
默认:单个空格
注意那个,逗号
#awk -F ":" -v OFS="===" '{print $1$2}' awk
line1-12
line2-12
awk 工作原理
#awk -F ":" -v OFS="===" '{print $1,$2}' awk
line1-1===2
line2-1===2
以文件passwd.txt为例:内容如下
现在通过分步演示说明上一条 awk 语句的执行过程:
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
#awk -F: 'BEGIN {print"user","passwd","UID","GID"}/^root/{print $1,$2,$3,$4}END{print"file output complete"}' passwd.txt
第一步:执行 BEGIN{action;...} 语句块中的语句
并没有处理passwd.txt内容,仅仅是打印了字符串,通常是用来当表头
#awk -F: 'BEGIN {print "user","passwd","UID","GID"}' passwd.txt
user passwd UID GID
第二步:从文件或标准输入 (stdin) 读取一行,然后执行 pattern{action;...}语句块,它逐行扫描文件,
从第一行到最后一行重复这个过程,直到文件全部被读取完毕.
指定以:分隔符
将每行记录分割之后,
#awk -F: 'BEGIN {print "user","passwd","UID","GID"}/^root/{print $1,$2,$3,$4}' passwd.txt
user passwd UID GID
root x 0 0
其中pattern指定条件为以root为行首,所以,只有一条记录是符合条件的
action 的执行操作就是print 第1,2,3,4字段内容
将每行记录分割之后,
----------------------------------------------------------------------------------
#awk -F: 'BEGIN {print "user","passwd","UID","GID"}{print $1,$2,$3,$4}' passwd.txt
user passwd UID GID
root x 0 0
bin x 1 1
daemon x 2 2
其中pattern没有指定,所以,所有的记录都是符合条件的
action 的执行操作就是print 第1,2,3,4字段内容.注意每个字段是属于内置变量,不要用引号."$1" 这样会被以字符串显示出来.
第三步:当读至输入流末尾时,执行 END{action;...}
最后只打印了一条信息在行末.
#awk -F: 'BEGIN {print "user","passwd","UID","GID"}/^root/{print $1,$2,$3,$4}END{print "file output complete" }' passwd.txt
user passwd UID GID
root x 0 0
file output complete
总结:
BEGIN 语句块在 awk 开始从输入流中读取行之前被执行,
这是一个可选的语句块,比如变量初始化,打印输出表格的表头等语句通常可以写在 BEGIN 语句块中
END 语句块在 awk 从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在 END 语句块中完成,
它也是一个可选语句块
pattern 语句块中的通用命令是最重要的部分,也是可选的.如果没有提供 pattern 语句块,则默认执行 {print},即打印每一个读取
到的行,awk 读取的每一行都会执行该语句块
print 格式
print item1, item2, ...
要点:
(1) 逗号分隔符
(2) 输出的各 item 可以字符串,也可以是数值;当前记录的字段
(3) 字符串,和特数的表示要用双引号."srt" "\t" "\n"
(4) 如省略 item,相当于 print $0 表示显示整行.
示例:
awk 变量
#awk -F: '{print $0}' /etc/passwd 等价于 #awk -F: '{print}' /etc/passwd
#awk -F: '{print $1"\t"$3}' /etc/passwd
#tail -3 /etc/fstab |awk '{print $2,$4}'
内置变量
-v 是声明变量
输入记录分隔符 RS
默认:换行符
输出记录分隔符 ORS
#awk -v RS="@" '{print $0}' awk2
a b c d
a b c d
---------------------------------------------
默认:换行(\n)
#awk -v ORS="行分隔" '{print $0}' awk
line1-1:2:3@a:b:c:d@E:F:G行分隔line2-1:2:3@a:b:c:d@E:F:G行分隔
---------------------------------------------
字段分隔符 FS
默认:单个空格
使用使用2种格式:
输出字段分隔符 OFS
#awk -F "@" '{print $2,$3}' awk
a:b:c:d E:F:G
a:b:c:d E:F:G
#awk -v FS="@" '{print $2,$3}' awk
a:b:c:d E:F:G
a:b:c:d E:F:G
---------------------------------------------
默认:单个空格
注意那个,逗号
#awk -F ":" -v OFS="===" '{print $1$2}' awk
line1-12
line2-12
NF:字段数量
#awk -F ":" -v OFS="===" '{print $1,$2}' awk
line1-1===2
line2-1===2
---------------------------------------------
NR:记录号
#awk -F: '{print NF}' /etc/passwd
7
#awk -F: '{print $(NF-1)}' /etc/passwd
/root
---------------------------------------------
FNR:分别统计各文件行数
#awk -F: '{print NR}' /etc/passwd 相当于打印行号
1
2
---------------------------------------------
FILENAME:当前文件名
#awk '{print FNR}' /etc/passwd /etc/fstab
---------------------------------------------
ARGC:命令行参数的个数,注意命令本身也算一个
#awk '{print FILENAME}' /etc/fstab
---------------------------------------------
ARGV:数组,保存的是命令行所给定的各参数
#awk '{print ARGC}' /etc/fstab /etc/inittab
3
---------------------------------------------
注意以下,ARGV[0],指的是命令本身
自定义变量
#awk 'BEGIN{print ARGV[0]}' /etc/passwd /etc/fstab
awk
#awk 'BEGIN{print ARGV[1]}' /etc/passwd /etc/fstab
/etc/passwd
#awk 'BEGIN{print ARGV[2]}' /etc/passwd /etc/fstab
/etc/fstab
用户定义的变量,有两种方法可以自定义变量.
方法一: - v变量名 = 变量值变量名区分字符大小写.注意变量名的命名规则可以参考之前的bash编程#awk - v 1abc = hunk'BEGIN {
引用外部的bash变量#
print 1abc
}'错误的变量命名awk: fatal: `1abc'is not a legal variable name#awk - v _1abc = hunk'BEGIN {
print _1abc
}'hunk方法二:在program中直接定义.变量定义与动作 (action)之间需要用分号";"隔开#awk'BEGIN {
name = "hunk";
blog = "http://blog.51cto.com/191226139";
print name,
blog
}'hunk http: //blog.51cto.com/191226139
总结
var = "bash-variable"#awk'BEGIN {
var
}'输出为空看到了吧,直接引用是不可以的下面使用 - v定义就能正常引用.所以 - v也是有特定用途的.#awk - v var2 = $var'BEGIN {
print var2
}'bash - variable另外,字段分割符也可以引用bash变量#awk - F "$var"使用 - F时,外部变量只能引有一次,后续就无法再次引用了#awk - v FS = "$var"'BEGIN {
print FS
}'
1.在awk中,只有在引用$0,$1等内置变量的值的时候才会用到"$",
引用其他变量时,不管是内置变量,还是自定义变量,都不使用"$",
而是直接使用变量名.2.先定义变量,再使用.3.awk的FS字段分隔符是支持正则表达式的,记得用双引号.line1 - 1 : 2 : 3@a: b: c: d@E: F: G#awk - F "[-:@]+"' {
}'awk.txt line1 1 2 3 a b line2 1 2 3 a b这里表示的是 []内的字符 - 或:或@可以作为分隔符,外面的 + 号是正则表达式的1个以上4.awk支持从文件读取指令#cat awk_file {
print $1,
$2,
$3,
$4,
$5,
$6
利用 printf 进行格式化输出
user = "username";
uid = "UID";
print user ":"$1,
uid ":"$3
}#awk - F ":" - f awk_file / etc / passwd username: root UID: 0 username: bin UID: 1
可以参考另一篇博客
printf 命令详解
printf 动作的用法与 printf 命令的用法非常相似,只是有略微的不同而已.
2 点不同:
第一点:
在awk中使用printf动作时,指定的"格式"与列($1)之间需要用"逗号"隔开,
而使用printf命令时,指定的格式与传入的文本不需要使用"逗号"隔开
awk printf 动作 printf "FORMAT" ,item1, item2, item3...
普通命令 printf "FORMAT" item1 item2 item3 ...
第二点:
#printf "%s\n" A B C
A
B
C
#echo "A B C"|awk '{printf "%s\n" $1}' $1前没有逗号
awk: (FILENAME=- FNR=1) fatal: not enough arguments to satisfy format string
`%s
A'
^ ran out for this one
#echo "A B C"|awk '{printf "%s\n",$1}' $1前有逗号
A
在awk中使用printf动作时,指定的"格式"与列($N)需要一一对应,而使用printf命令时,则不需要
awk printf 动作 printf "FORMAT FORMAT FORMAT " ,item1, item2, item3...
普通命令 printf "FORMAT" item1 item2 item3 ...
以上 2 点需要特别注意.
#printf "%s\n" A B C
A
B
C
#echo "A B C"|awk '{printf "%s\n%s\n%s\n",$1,$2,$3}' 格式与列一一对应
A
B
C
操作符
算术运算
x+y, x-y, x*y, x/y, x^y, x%y
-x: 转换为负数
+x: 转换为数值
#awk 'BEGIN {printf "%d\n", -(3-1)}'
-2
字符串操作符
#awk 'BEGIN {print 3+5}'
8
#awk 'BEGIN {printf "%f\n",1/3}' 比bash要强,支持浮点数
0.333333
没有符号的操作符
#awk 'BEGIN{print "abc-edf"}'
赋值操作符
比较操作符
=, +=, -=, *=, /=, %=, ^= ++, --
#awk 'BEGIN{i=10;m+=i;print i}'
10
#awk 'BEGIN{i=10;++i;print i}'
11
#awk 'BEGIN{unset i;i=10;++i;print i}'
11
操作符 含义 示例
< 小于 a < b
<= 小于等于 a <= b
== 等于 a == b
!= 不等于 a != b
>= 大于等于 a >= b
> 大于 a > b
~ 与正则匹配(包含的关系) a ~ b
!~ 与正则不匹配 a !~ b
使用正则表达式时的注意要点
#awk -F: '$3 < 10 {printf "= %-8s m\n", NR,$1,$3}' /etc/passwd
1 root 0
2 bin 1
3 daemon 2
4 adm 3
5 lp 4
6 sync 5
7 shutdown 6
8 halt 7
9 mail 8
#awk -F: '$1 == "hunk" {print NR,$1,$3}' /etc/passwd
32 hunk 500
在使用如~ 这种匹配关系时,必须加双引号或者 / / .与搜索匹配正则位置的语法不一样.
匹配正则,注意是包含的关系.
不匹配正则
#awk '$0 ~ "root" {print NR,$1,$3}' /etc/passwd
1 root:x:0:0:root:/root:/bin/bash
11 operator:x:11:0:operator:/root:/sbin/nologin
awk 命令在使用扩展正则表达式,需要将正则表达式放入了 "/ /" 中. 如果正则中包含 "/",则需要进行转义. 比如说:
#awk '$0 !~ "/bin/bash" {print NR,$1,$3}' /etc/passwd
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
当使用 {a,b},{a,} 这种次数匹配的正则表达式时,需要配合 --posix 选项或者 --re-interval 选项
#df | awk '/\/dev\/sd/{print $0}'
/dev/sda3 8652808 2437492 5769108 30% /
/dev/sda1 487652 35608 426444 8% /boot
#awk '/(abc){2,2}/{print $0}' demo.txt
输出为空
这种写法貌似不支持
#awk --re-interval '/(abc){2,2}/{print $0}' demo.txt
abcabckkal
#awk --posix '/(abc){2,2}/{print $0}' demo.txt
abcabckkal
#awk --re-interval '/(abc){2,}/{print $0}' demo.txt
abcabckkal
#awk --re-interval '/(abc){,2}/{print $0}' demo.txt
输出为空
awk 的行范围模式
语法:
awk / 正则表达式1 /,/ 正则表达式2 /{动作}
#awk '/^lp/,/^games/{print NR,$0}' /etc/passwd
匹配以lp为行首到以games行首之间的范围
逻辑操作符
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
&& (与),|| (或),! (非)
AWK (一)
#seq 1 10 | awk '$1 >= 3 && $1 <= 6 {print $0}' && (与)
3
4
5
6
#seq 1 10 | awk '$1 == 3 || $1 == 6 {print $0}' || (或)
3
6
#seq 1 10 | awk '!($1 < 5) {print $0}' ! (非)
5
6
7
8
9
10
来源: http://www.bubuko.com/infodetail-2459314.html