> 文章列表 > 三剑客----awk

三剑客----awk

三剑客----awk

在Linux/Unix系统中,awk是一个功能强大的编辑工具,逐行读取输入文本,默认以空格或tab键作为分隔符分隔,并按模式或者条件执行编辑命令。

awk信息的读入也是逐行指定的匹配模式进行查找,对符合条件的内容进行格式化输出或者过滤处理,可以在无交互的情况下实现相当复杂的操作,被广泛应用于shell脚本,完成各种自动化配置任务。

awk的工作过程:

第一步:执行BEGIN{action;...}语句块中的语句

第二步:从文本或标准输入(stdin)读取一行,然后执行pattern{action;...}语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕。

第三步:当读至输入流末尾时,执行END{action;...}语句块

BEGIN语句块在awk开始从输入流读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中。

END语句块在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句 块中完成,它也是一个可选语句块。

pattern语句块中的通用命令是最重要的部分,也是可选的。如果没有提供pattern语句块,则默认执行{print},即打印 每一个读取到行,awk读取的每一行都会执行该语句块。

 工作原理

sed命令常用于一整行的处理,而awk比较倾向于将一行分为多个“字段”然后再进行处理,切默认情况下字段的分隔符为 空格或TAB键。

awk的基本格式

awk 选项 ‘模式或条件 { 操作}’ 文件1 文件2

-F “分隔符”指明输入时用到的字段分隔符,默认的分割符是若干个连续空白符。

用单引号:'模式或条件{条件}'

{ }外指定条件 {}内指定操作 用逗号指定连续的行,用 || 指定不连续的行,&&表示“且”

内建变量,不能用双引号括起来,不然系统会把它当成字符串。

内置变量:

$0: 当前处理的行的整行内容

$n: 当前处理行的第n个字段 (第n列)

NR: 当前处理的行的行号(序数)

NF:当前处理的行的字段个数。

$NF代表最后一个字段。

FS:列分隔符。指定每行文本的字段分隔符,输入内容的的分隔符。默认为空格或制表位。与“-F”作用相同 用-F可以不 加单引号,必须用=“”

OFS:输出内容的列分隔符

FILENAME:被处理的文件名

RS:行分隔符 。 awk从文件读取资料时,将根据RS的定义把资料切割成许多条记录,而awk一次仅读入一条记录进行 处理。预设值是“\\n”换行。

awk '{print}' 默认{print}前有一个1,0是不打印

awk '{print $1}' 文件名 取所有行的第一列(因为是对行生效)

awk '{print NR,$0}' 文件名 打印行号和内容

awk ' NR==3{print}' 文件名 打印第三行

awk 'NR==3,NR==5{print}' 文件名 打印三到五行

awk 'NR==3;NR==5{print}' 文件名 打印第三和第五行

awk '(NR>=4)&&(NR<+9){print}' 文件名 打印第四到第九行内容(正则表达方式)

awk ' NR%2==0{print}' 文件名 取偶数行

awk ' NR%1==0{print}' 文件名 取奇数行

awk '{getline;print $0}' 文件名 取偶数行

awk '{print $0;getline }' 文件名 取奇数行

求幂:awk 'BEGIN{print 3**2}' 三的二次方

           awk 'BEGIN{print 3^2}' 三的二次方

getline工作工程

当getline左右无重定向符号(“<”)或者管道符号(“|”)时,awk首先读取的事第一行,而getline获取的是光标跳转至下 一行的内容。

ls | awk '{getline line; print $0,line;}' 作用等同于ls

文本内容匹配过滤打印

awk '/^root/{print}' /etc/passwd 打印目录下以root开头的行

awk '/bash$/{print}' /etc/passwd 打印目录下以bash结尾的行

BEGIN打印模式

格式:awk 'BEGIN{...};{...};END{...} '文件名

处理过程: 1、在awk处理指定的文本之前先要执行BEGIN模式里的命令操作

2、中间的{...}是真正用于处理文件的命令操作

3、在awk处理完文件后才会执行END{...}

awk 'BEGIN{x=1};{x++}END{print x}' 文件名 循环行数进行+1

awk -F: '{print $1}' /etc/passwd 以冒号为分隔符打印/etc/passwd的第一列

awk -F: '{print $2}' /etc/passwd 以冒号为分隔符打印/etc/passwd的第二列(密码占位符)

-v的用户:变量赋值(针对分隔符)

awk -v FS=':' -v OFS='==' '{print $1,$3}' /etc/passwd 第一和第二列,如果一到三只能$1,$2,$3 ▲

echo $PATH | awk -v RS=':' '{print $0}' 默认换行输出环境变量

BEGIN模式制定

head -n5 /etc/passwd | awk 'BEGIN{FS=':'};{print $5}' 打印冒号作为分隔符的第五列 (less more 分页查看)

条件判断打印

awk -F: '$3>500{print $0}' /etc/passwd 打印第三列大于500的

程序用户500-999 普通用户1000-65534

awk -F:'{if ($3>500){print $0 }}' /etc/passwd 打印第三列大于500的

awk -F:'!($3>10){print $0}' /etc/passwd 第三列小于等于十的全部打印(取反判断)

awk三元表达式

格式:awk '(条件表达式)?(A表达式或者值):(B表达式或者值)'

awk -F:'{max=($3>=$4)?$3:$4;{print max,$0}}' /etc/passwd | sed -n '1,6p' 比较passwd文件中以":"为分割的第三个和 第四个字段的大小。

?:运算符是if-else语句的简写,因此此行等效于 if ($3>= $4) {max=$3} else {max=$4}

取比较结果的最大值,赋值给变量max,并且输出max行的所有内容,然后打印其中的1-6行。

awk精确筛选

$n(><==):用于对比数值

$n~"字符串":代表第n个字段包含某个字符串

$n!~"字符串":代表第n个字段不包含某个字符串

$n=="字符串":代表第n个字段为某个字符串

$n!="字符串":代表第n个字段不为某个字符串

$NF:代表最后一个字段

输出第七个字段包含‘bash’所在行的第一个字段和最后一个字段

awk -F: ' $7~ "bash"{print $1,$NF}' /etc/passwd

不包含输出第七个字段包含‘bash’所在行的第一个字段和最后一个字段

awk -F: '$7!~"nologin"{print $1,$NF}' /etc/passwd

第六段包含/home/xny和第七个字段包含bin/bash的行 打印第一和最后字段:

awk -F:'($6=="/home/xny")&&($7=="/bin/bash"){print $1,$NF}' /etc/passwd

awk分隔符用法

RS默认分隔符\\n 换行 awk从资料中读取资料时,将根据RS的定义把资料切割成许多条记录,而awk一次仅读入一条记录进行处理。也可以使 用BEGIN模式在操作前进行行分隔符的改变。

以冒号为分隔符的全部内容进行打印,以默认RS\\n进行分隔打印(NR序号)

echo $PATH | awk 'BEGIN{RS=":"};{print NR,$0}'

指定输出的分隔符:

OFS:输出内容的列分隔符($n=$n用于激活,否则不生效,n且必须存在)

echo a b c d | awk '{OFS=":";$1=$1;print $0}'

echo a b c d | tr " " ":"

echo a b c d | awk 'BEGIN{OFS=":"};{$1=$1;print $0}' 结果:a:b:c:d

awk结合数组运用

awk 'BEGIN{a[0]=10;a[1]=20;a[2]=30......;print a[1]}'

形成数组遍历

awk 'BEGIN{a[0]=10;a[1]=20;a[2]=20;a[3]=30;for(i in a)print i,a[i]}' 在awk中打印变量不需要加$

awk '{a[$1]++};END{for(i in a){print i,a[i]}}' 文件名

遍历几次由行数决定 ★取小数点几位和取整数 (printf:f调用%.f方法)

result=$(awk 'BEGIN{printf "%.2f",2.32332*2.3213}') 取小数点2位

result=$(awk 'BEGIN{printf "%.F",2.32332*2.3213}') 取整(四舍五入)

简单日志分割

awk '{print $1, $7, $9}' /var/log/messages

提取主机名放入host文件:

awk -F'[ .]+' '{print $2}' 111.txt >host

磁盘可用容量(G)

df | grep -w centos-root | awk '{sum+=$4} END{print "磁盘可用容量:"sum/1024/1024}'

df -h | awk '$NF=="/"{print $4}'

etc下文件的大小和(M)

ls -l /etc/ | awk '/^-/ {sum+=$5} END{print "文件总大小:"sum/1024“M”}