Linux命令——awk命令
Linux命令——awk命令
1.简介
AWK是一个优良的文本处理工具,Linux及Unix环境中现有的功能最强大的数据处理引擎之一。
数据可以来自标准输入(stdin)、一个或多个文件,或其它命令的输出。
它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。
它在命令行中使用,但更多是作为脚本来使用。
awk有很多内建的功能,比如数组、函数等,这是它和C语言的相同之处,灵活性是awk最大的优势。
简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。
awk有3个不同版本: awk、nawk和gawk,未作特别说明,一般指gawk,gawk 是 AWK 的 GNU 版本。
awk其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母。
实际上AWK的确拥有自己的语言: AWK程序设计语言 , 三位创建者已将它正式定义为“样式扫描和处理语言”。
它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其他的功能。
2.命令格式
awk [options] 'pattern + {action}' [filenames...] |
尽管操作可能会很复杂,但语法总是这样。awk通常用来格式化文本文件中的信息,是以文件的一行为处理单位,每接收文件的一行,然后执行相应的命令,来处理文本。其中pattern表示AWK在数据中查找的内容,而action是在找到匹配内容时所执行的一系列命令。花括号{}不需要在程序中始终出现,但它们用于根据特定的模式对一系列指令进行分组。pattern表示的正则表达式,用斜杠括起来,action 对匹配的行进行处理。
注意:
(1)pattern缺省为1,action缺省为{print}。
(2)pattern + {action}可以同时存在多个,每个pattern之间的关系是或,只要当前行匹配pattern,则执行pattern后大括号中的commands。
3.常用命令选项
-F fs,--field-separator fs:使用字符串fs作为域分隔符。可以同时指定多个域分隔符,此时需要使用一对中括号括起来。例如使用-和|可写作 -F '[-|]'。如果用[]作为分隔符,可写作-F '[][]'。不指定分隔符,默认为空格和Tab。需要注意,awk命令使用-F' '显示指定空格时,tab也会被作为分隔符。 |
4.调用awk方式
有三种方式调用awk。
(1)命令行方式。
awk [-F field-separator] 'pattern + {action}' input-file(s) |
其中,commands 是真正awk命令,[-F域分隔符]是可选的。 input-file(s) 是待处理的文件。 在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域。通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。
(2)shell脚本方式。
将所有的awk命令插入一个文件,脚本中在首行注明使用awk命令来解析执行,相当于将shell脚本首行的:#!/bin/sh
换成:#!/bin/awk
,最后通过键入脚本名称来调用。
(3)将所有的awk命令插入到一个单独文件,然后使用-f选项调用。
awk -f awk-script-file input-file(s) |
其中,-f选项加载awk-script-file中的awk脚本,input-file(s)跟上面的是一样的。
5.awk内置变量
awk有许多内置变量用来设置环境信息,这些变量可以被改变,下面给出常见的内置变量说明。
$n 当前记录的第n个字段,n从1开始,字段间由FS分隔 |
6.awk编程示例
6.1基础打印输出
(1)假设last -n 5的输出如下:
[root@www ~]# last -n 5 <==仅取出前五行 |
如果只是显示最近登录的5个帐号:
#last -n 5 | awk '{print $1}' |
awk工作流程是这样的:
读入有’\n’换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域,0则表示所有域,0则表示所有域,0则表示所有域,1表示第一个域,n表示第n个域。
默认域分隔符是”空白键”或”[tab]键”,所以n表示第n个域。默认域分隔符是”空白键”或”[tab]键”,所以n表示第n个域。
默认域分隔符是”空白键” 或 “[tab]键”,所以1表示登录用户,$3表示登录用户ip,以此类推。
(2)如果想显示/etc/passwd配置文件中的账户以及账户对应的shell,而账户与shell之间以tab键分割。
#cat /etc/passwd |awk -F ':' '{print $1"\t"$7}' |
注意,这里使用了-F指定域分隔符为’:’。
(3)如果只是显示/etc/passwd的账户和账户对应的shell,而账户与shell之间以逗号分割,而且在所有行添加列名name,shell,在最后一行添加”blue,/bin/nosh”。
cat /etc/passwd |awk -F ':' 'BEGIN {print "name,shell"} {print $1","$7} END {print "blue,/bin/nosh"}' |
awk工作流程是这样的:先执行BEGING,然后读取文件,读入有/n换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域,0则表示所有域,0则表示所有域,0则表示所有域,1表示第一个域,$n表示第n个域,随后开始执行模式所对应的动作action。接着开始读入第二条记录······直到所有的记录都读完,最后执行END操作。
(4)搜索/etc/passwd有root关键字的所有行。
#awk -F: '/root/' /etc/passwd |
上面三种是awk的action的使用示例,而这种是pattern的使用示例,匹配了pattern(这里是root)的行才会执行action(没有指定action,默认输出每行的内容)。
搜索支持正则表达式,例如找root开头的。
awk -F: '/^root/' /etc/passwd |
(5)搜索/etc/passwd有root关键字的所有行,并显示对应的shell。
# awk -F: '/root/{print $7}' /etc/passwd |
这里是awk的pattern+action示例用法,同时指明了action是{print $7}。
(6)打印/etc/passwd第三行的第一列和第二列。
awk -F: 'NR==3{print $1,$2;}' /etc/passwd |
6.2.awk在每一列后添加字符串后输出
设定变量内容:
a="/test.html /dir1 /abc.txt" |
希望得到
echo $a |
如何用awk实现。
解决办法:
echo $a|awk '{for(i=1;i<=NF-1;++i){printf "-execute=%s ",$i}}{print "--exclude="$NF""}' |
后者是网友给出的答案,和我上面的写法是差不多的,只是对printf在使用形式上有所差别而已。第二种方法print “”是用于换行,print每次输出后默认进行换行。
6.3shell编程使用awk浮点运算保留两位小数
a=3 |
或者:
c=$(awk -v n=$a -v m=$b 'BEGIN{printf "%.2f",n*100/m}') |
-v表示定义awk的变量!v是variable的首字母。输出:c:30.00%。
6.4awk访问shell变量
awk默认是无法访问shell变量的,我所知道的有三种方法。 方法一:awk -v 选项让awk 里使用shell变量。
var0=dablelv0 |
输出: dablelv0 dablelv1 注意: BEGIN必须大写,awk的{action}必须要使用单引号括起来。
方法二:'"$var"'
这种写法是老外常用的写法。如:
var="test" |
这种写法其实际是双括号变为单括号的常量,传递给了awk。
如果var中含空格,为了shell不把空格作为分格符,应该如下使用:
var="this is a test" |
方法三:export 变量,将变量设置为临时会话环境变量,仅在当前shell会话中有效。在awk中使用ENVIRON["var"]
形式访问变量。
var="this is a test" |
6.5awk执行shell命令
awk执行shell命令有两种方法。 方法一:使用awk的system()函数。
export var=dablelv |
输出:dablelv
注意:一定要使用export将变量设置为临时环境变量,因为awk的system()实际上是新建了一个shell进程来执行给定的shell命令,否则无法访问父进程的变量。
方法二:使用使用print cmd | "/bin/bash"
var="this is a test" |
输出:this is a test
注意:
(1)指定bash的时候需要双引号括起来;
(2)方法二与方法一的区别在于方法二是将变量在awk解析后再通过管道传给shell,所以无需将变量设置为临时环境变量,因为shell接收到的变量已经是变量的值。
7.awk常见问题
(1)awk以空格为分隔符Tab也被作为域分隔符。现在只以空格为分隔符,需要使用中括号的方式。不使用中括号,则仍然会将Tab作为分隔符。
#错误的写法 |