shell 学习第十七天----awk 命令
使用 awk 重新编排字段
awk 非常擅长处理结构化数据和生成表单。和 sed 和 grep 很相似。由于 awk 具备各种及哦啊本语言的特点,所以可以把它看做是一种脚本语言。
先来看个案例,只查看 /etc/passwd/ 目录下的用户名和组名
awk -F: ‘{print $1,$5}’ /etc/passwd
意思是: 使用: 来分割这一行,把这一行的第一和第五个字段打印出来。
调用 awk
- 第一种方式:
awk [-F 分隔符] 'commands' input-file(s)
这里的commands
是真正的awk
命令,[-F 分隔符] 适可选的,awk
默认使用空格分隔,因此如果要浏览域间有空格的文本,不必指定这个选项,但如果浏览如 passwd 文件,此文件各域使用冒号作为分隔符,则必须使用-F
选项:awk -F : 'commands' input-file
- 第二种方式:将所有
awk
命令插入一个文件,并使awk
程序可执行,然后用awk
命令解释器作为脚本的首行,以便通过键入脚本名称来调用它 - 第三种方式:将所有
awk
命令插入一个单独文件,然后调用,如:awk -f awk-script-file input-file-f
选项指明在文件awk-script-file
的awk
脚本,input-file
是使用awk
进行浏览的文件名
任何 awk
语句都是由模式和动作组成,在一个 awk
脚本中可能有许多语句。模式部分决定动作语句何时触发及触发事件。动作即对数据进行的操作,如果省去模式部分,动作将时刻保持执行状态。
模式可以是任何条件语句或复合语句或正则表达式,模式包含两个特殊字段 BEGIN
和 END
,使用 BEGIN 语句设置计数和打印头,BEGIN
语句使用在任何文本浏览动作之前,之后文本浏览动作依据输入文件开始执行;END
语句用来在 awk
完成文本浏览动作后打印输出文本总数和结尾状态标志,有动作必须使用 {} 括起来
实际动作在大括号 {} 内指明,常用来做打印动作,但是还有更长的代码如 if
和循环 looping
语句及循环退出等,如果不指明采取什么动作,awk
默认打印出所有浏览出的记录
awk
执行时,其浏览标记为 $1,$2...$n
,这种方法称为域标记。使用 $1,$3
表示参照第 1 和第 3 域,注意这里使用逗号分隔域,使用 $0
表示使用所有域。例
-
awk -F :‘{print $0}’ /etc/passwd
// 表示打印所有域并把结果重定向到 /etc/passwd 中 (所谓的域就是某一行中的字段) -
awk -F : ‘{print $0}’ /etc/passwd
/// 在屏幕上显示出来 -
awk ‘{print $1,$4}’ /etc/passwd
// 只打印第一和第四域 (第一和第四字段) -
awk -F: ‘BRGIN{print”hahaha\n---”}{print $1 “\t” $4}’ /etc/passwd
// 表示打印头信息,在输入的内容的第一行前加上”hahaha”,同时内容之间用 tab 键分开。 awk -F: 'BEGIN{print"hahaha\n---"}{print $1"\t"$4}END{print"end\n"}' /etc/passwd
// 这个代表的意思是说打印开头结尾
awk 的条件匹配符
<、<=、==、!=、>=、~ 匹配正则表达式、!~ 不匹配正则表达式
- 匹配:
awk -F: '{if($1~/root/)print $0}' /etc/passwd
// 在 /etc/passwd 这个文件中,如果某条记录的第一个字段含有 root 就打印整条记录到屏幕上,注意,只要包含就行。 - 精确匹配 :
awk -F: '$1=="root"{print $0}' /etc/passwd
// 某行中的第一个字段必须等于 root 才打印。 - 不匹配 :
awk -F: '$0!~"root"{print $0}' /etc/passwd
打印整条不包含 root 的记录,使用双引号或者反斜杠都是一样的。
其他的操作符具体不在介绍。
awk 的设计目的就是操作记录与字段:awk 读取输入记录 (通常是一些行),然后自动将各个记录且分为字段。awk 将每条记录内的字段树木,存储到内建变量 NF。通过上面的例子,差不多已经总体上有了一定得了解:awk '{print $NF}'
打印最后一行,比较特殊的字段是编号 0,表示整条记录。
awk 内置变量
ARGC 命令行参数个数
ARGV 命令行参数排列
ENVIRON 支持队列中系统环境变量的使用
FILENAME awk 浏览的文件名
FNR 浏览文件的记录数
FS 设置输入域分隔符,等价于命令行 -F 选项
NF 浏览记录的域的个数
NR 已读的记录数
OFS 输出域分隔符
ORS 输出记录分隔符
RS 控制记录分隔符
案例
统计 /etc/passwd
: 文件名,每行的行号,每行的列数,对应的完整行内容:
awk -F ':' '{print"filename:"FILENAME",linenumber:"NR",columns:"NF",linecontent:"$0}' /etc/passwd
除了 awk 的内置变量,awk 还可以自定义变量。
例如:
统计 /etc/passwd
的行数
awk '{count++}END{print count}' /etc/passwd
count 是自定义变量,这里没有初始化 count,虽然默认是 0,但是妥当的做法还是初始化为 0。
awk 'BEGIN{count=0}{count=count+1}END{print count}' /etc/passwd
例如:
统计某个文件夹下的文件占用的字节数
ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print"[end]size is ",size}'
如果按照 M 为单位显示
ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print"[end]size is ",size/1024/1024,"M"}'
小结:
- 如果需要从输入的数据文件夹中取出特定的文本行,主要的工具为 grep 程序。
sed
是处理简单字符串替换的主要工具。大部分 shell 脚本在使用sed
时几乎都是用来做替换的操作。- “从最左边开始,扩展至最长” 这个法则描述了匹配的文本在何处匹配以及匹配扩展到多长。在使用
sed,awk
或其他交互式文本编辑程序时,这个法则相当重要。 - cut 命令用以剪下选定的字符范围或字段。join 则是用来结合记录中具有共同键值的字段的文件。
awk
多半用于简单的“单命令行程序”,当你想要只显示选定的字段,或是重新安排行内的字段顺序时,就是awk
排上用场的时候了。由于awk
还是编程语言,即使在尖端的程序里,他也能发挥强大的作用。