返回首页 两个月精通 Shell 脚本

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-fileawk 脚本,input-file 是使用 awk 进行浏览的文件名

任何 awk 语句都是由模式和动作组成,在一个 awk 脚本中可能有许多语句。模式部分决定动作语句何时触发及触发事件。动作即对数据进行的操作,如果省去模式部分,动作将时刻保持执行状态。

模式可以是任何条件语句或复合语句或正则表达式,模式包含两个特殊字段 BEGINEND,使用 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 还是编程语言,即使在尖端的程序里,他也能发挥强大的作用。