13.shell awk基础
- awk作用
- awk语法结构
- awk脚本结构
- awk工作原理
- awk内部变量
- awk格式输出
- awk模式匹配
- RegExp示例
- 运算符匹配示例
- 布尔运算符匹配示例
- 运算符匹配示例
- awk条件判断
- if判断
- awk循环语句
- while循环
- for循环
awk是一种强大的文本处理工具,主要用于对文本和数据进行处理。
awk作用
awk命令擅长对文件列进行操作 (awk在识别列信息的时候,默认以空格为分隔符,来识别列信息的)
awk命令擅长对数据文件进行分析
awk命令可以编写脚本
awk可以进行算术运算
awk语法结构
awk options 'pattern {action}' file
awk 选项 '模式{动作}' 文件
options:是一些选项,用于控制 awk 的行为。
-F : 指定输入字段的分隔符,默认是空格。使用这个选项可以指定不同于默认分隔符的字段分隔符。
-v :设置 awk 内部的变量值。可以使用该选项将值传递给 awk 脚本中的变量。
-f : 指定一个包含 awk 脚本的文件。这样可以在文件中编写较大的 awk 脚本,然后使用 -f 将其加载。
pattern:是用于匹配输入数据的模式。如果省略,则 awk 将对所有行进行操作。
{action}:是在匹配到模式的行上执行的动作。如果省略,则默认动作是打印整行。
awk 'BEGIN {命令} pattern {命令} END {命令}' 文件
BEGIN:处理文件前执行的动作
END:处理文件后执行的动作
pattern:模式,每一行都执行的动作
BEGIN和END里的命令只是执行一次,pattern里的命令会匹配每一行去处理
awk脚本结构
vim test.awk
#处理文件前执行的动作
BEGIN {
printf "--------\n" #这里面放的是执行前的语句
}
#处理文件的过程中
{
printf "----------\n" #这里面放的是处理每一行时要执行的语句
}
#文件处理完后执行的动作
END {
printf "-----------\n" #这里面放的是处理完所有的行后要执行的语句
}
脚本执行
awk -f test.awk 要处理的文件
awk工作原理
逐行读取信息
判断是否为需要的信息
如果是满足条件的信息,就对满足条件的信息做相应的处理
如果不是满足条件的信息,就会继续读取下一行信息
以该命令为例: awk -F: ‘{print $1,$3}’ /etc/passwd
1.awk将文件中的每一行作为输入, 并将每一行赋给内部变量$0, 以换行符结束
2.awk开始进行字段分解,每个字段存储在已编号的变量中,从$1开始[默认空格分割]
3.awk默认字段分隔符是由内部FS变量来确定, 可以使用-F修订
4.awk行处理时使用了print函数打印分割后的字段
5.awk在打印后的字段加上空格,因为$1,$3 之间有一个逗号。逗号被映射至OFS内部变量中,称为输出字段分隔符, OFS默认为空格.
6.awk输出之后,将从文件中获取另一行,并将其存储在$0中,覆盖原来的内容,然后将新的字符串分隔成字段并进行处理。该过程将持续到所有行处理完毕.
awk内部变量
内置变量 | 含义 |
---|---|
$0 | 整行内容 |
$1-$n | 当前行的第1-n个字段 |
NF | 当前行的字段个数,也就是多少列 |
NR | 当前的行号,从1开始计数 |
FS | 输入字段分隔符。不指定默认以空格或tab键分割 |
RS | 输入行分隔符。默认回车换行 |
OFS | 输出字段分隔符。默认为空格 |
ORS | 输出行分隔符。默认为回车换行 |
测试文件准备
cat awk_test.txt
ll 1990 50 51 61
kk 1991 60 52 62
hh 1992 70 53 63
jj 1993 80 54 64
mm 1994 90 55 65
1.awk内置变量,$0保存当前记录的内容
awk '{print $0}' awk_test.txt
2.awk内置变量,FS指定字段分割符,默认以空白行作为分隔符
awk '{print $1}' awk_test.txt
FS指定字段分割符
awk -F '[: ]+' '{print $1}' awk_test.txt
3.awk内置变量NF,保存每行的最后一列
awk '{print NF,$NF}' awk_test.txt
打印NF和$NF
NF 当前行有多少列
$NF 最后一列内容
4.awk内置变量NR,表示记录行号。
awk '{print NR,$0}' awk_test.txt
如果想打印第二行到第三行的内容怎么办?
awk 'NR>1&&NR<4 {print NR,$0}' awk_test.txt
如果既想打印第三行,又想打印第一列?
awk 'NR==3 {print $1}' awk_test.txt
5.awk内置变量RS,输入行分隔符。
awk 'BEGIN{RS="--"} {print $0}' awk-test.txt
默认以换行为行分隔符,这里指定了 ‘–’ 为行分隔符,原本一行的内容,分为了三行。
6.awk内置变量,“OFS输出字段分隔符”,初始情况下OFS变量是空格。
awk 'BEGIN{RS="--";FS="|";OFS=": "} {print $1,$2}' awk-test.txt
以–为行分隔符,以|为输入字段分隔符,输出的内容将以:为分隔符展示
7.awk内置变量,“ORS输出行分隔符”,默认行分割符为\n
awk 'BEGIN{RS="--";FS="|";OFS=": ";ORS="*****"} {print $1,$3}' awk-test.txt
awk格式输出
awk可以通过printf函数生成非常漂亮的数据报表。
格式符 | 含义 |
---|---|
%s | 打印字符串 |
%d | 打印十进制数(整数) |
%f | 打印一个浮点数(小数) |
%x | 打印十六进制数 |
修饰符 | 含义 |
- | 左对齐 |
+ | 右对齐 |
printf默认没有分隔符,输出是一坨
awk 'BEGIN{FS=":"} {printf $1}' passwd
2.加入换行,格式化输出。
awk 'BEGIN{FS=":"} {printf "%s\n",$1}' passwd
3.使用占位符美化输出。
awk 'BEGIN{FS=":"} {printf "%20s %20s\n",$1,$7}' passwd
4.默认右对齐,-表示左对齐。
awk -F":" '{printf "%-20s %-20s\n",$1,$7}' passwd
zhangsan 80 90 82 75
lisi 91 76 97 98
wangwu 86 98 89 97
oldsix 87 99 78 99
sun 76 96 85 69
BEGIN { #行处理前
printf "%-20s %-20s %-20s %-20s %-20s \n",
"Name","Chinese","Math","PE","Engilsh"
}
{ #行处理中
printf "%-20s %-20s %-20s %-20s %-20s \n",
$1,$2,$3,$4,$5
}
awk模式匹配
awk第一种模式匹配:RegExp
awk第二种模式匹配:关系运算匹配
RegExp示例
1.匹配/etc/passwd文件行中含有root字符串的所有行。
awk -F":" '/root/{print $0}' passwd
2.匹配/etc/passwd文件行中以root开头的行。
awk '/^root/' passwd
3.匹配/etc/passwd文件行中/bin/bash结尾的行。
awk '/\/bin\/bash$/' passwd
运算符匹配示例
符号 | 含义 |
---|---|
< | 小于 |
> | 大于 |
<= | 小于等于 |
>= | 大于等于 |
== | 等于 |
!= | 不等于 |
~ | 匹配正则表达式 |
!~ | 不匹配正则表达式 |
1、以:为分隔符,匹配/etc/passwd文件中第3个字段小于50的所有行信息
awk -F":" '$3<50{print $0}' passwd
2、以:为分隔符,匹配/etc/passwd文件中第7个字段为/bin/bash的所有行信息
awk -F":" '$7=="/bin/bash" {print $0}' passwd
3、以:为分隔符,匹配/etc/passwd文件中第7个字段不为/bin/bash的所有行信息
awk -F":" '$7!="/bin/bash" {print $0}' passwd
4、以:为分隔符,匹配/etc/passwd文件中第3个字段包含3个数字以上的所有行信息
awk -F":" '$3~/[0-9]{3,}/{print $0}' passwd
布尔运算符匹配示例
符号 | 含义 |
---|---|
|| | 或 |
&& | 与 |
! | 非 |
1、以:为分隔符,匹配passwd文件中包含ftp或mail的所有行信息
awk -F":" '/ftp/||/mail {print $0}/' passwd
2、以:为分隔符,匹配passwd文件中第3个字段小于50并且第4个字段大于50的所有行信息
awk -F":" '$3<50&&$4>50 {print $0}' passwd
3.匹配没有/sbin/nologin的行。
awk -F":" '$0 !~ /\/sbin\/nologin$/ {print $0}' passwd
运算符匹配示例
运算符 | han yi |
---|---|
+ | 加 |
- | 减 |
* | 乘 |
/ | 除 |
% | 模(取余) |
1、计算学科平均分数
zhangsan 80 90 82 75
lisi 91 76 97 98
wangwu 86 98 89 97
oldsix 87 99 78 99
sun 76 96 85 69
vim grades.awk
BEGIN {
printf "%-20s %-20s %-20s %-20s %-20s %-20s \n",
"Name","Chinese","Math","PE","Engilsh","AVG"
}
{
sum=$2+$3+$4+$5
avg=sum/(NF-1)
}
{
printf "%-20s %-20s %-20s %-20s %-20s %-20s \n",
$1,$2,$3,$4,$5,avg
}
awk -f grades.awk grades.txt
核对一下平均分
echo " 80 90 82 75" |xargs |sed 's# #+#g'|bc
awk条件判断
if判断
if语句格式:{if(表达式) {语句;语句;....}}
1.以:为分隔符,打印当前管理员用户名称
BEGIN {
FS=":"
}
{
if($3==0){
print $1,"is administrator"
}
}
2.以:为分隔符,统计系统用户数量
BEGIN{ #行处理前
FS=":"
}
{ #行处理中
if($3>0 && $3<1000){
i++
}
}
END{ #行处理后
print "系统用户数量为:"i
}
3.以:为分隔符,统计普通用户数量
BEGIN{
FS=":"
}
{
if($3>1000){
i++
}
}
END{
print "普通用户数量为:"i
}
4.以:为分隔符,只打印passwd中第3个字段的数值在50-100范围内的行信息
awk 'BEGIN{FS=":"}{if($3>50 && $3<100){print $0}}' passwd
或
BEGIN{
FS=":"
}
{
if ($3>50 && $3<100){
print $0
}
}
日常使用中更推荐awk脚本的形式,方便阅读,可持续使用,命令行的形式无法重复使用。
if...else语句格式:{if(表达式) {语句;语句;...} else{语句;语句;...}}
1.以:为分隔符,判断第三列如果等于0,则打印该用户名称,如果不等于0则打印第七列。
awk 'BEGIN{FS=":"}{if($3==0){print $1}else{print $7}}' passwd
或
BEGIN{
FS=":"
}
{
if($3==0){
print $1
}
else{
print $7
}
}
2、以:为分隔符、判断第三列如果等于0,则打印管理员出现的个数,否则都视为系统用户,并打印它的个数。
awk 'BEGIN{FS=":";OFS="\n"} {if($3==0){i++} else{j++}} END{print i "管理员",j "系统用户" }' passwd
BEGIN{
FS=":"
OFS="\n"
}
{
if($3==0){
i++
}
else{
j++
}
}
END{
print i "管理员",j "系统用户"
}
if...else语句格式:{if(表达式1) {语句;语句;...} else if(表达式2){语句;语句;...} else{语句;语句;...}}
1.使用awk 打印出当前/etc/passwd文件管理员有多少个,系统用户有多少个,普通用户有多少个
BEGIN{
FS=":"
OFS="\n"
}
{
if($3==0){
i++
}
else if($3>0 && $3<1000 ){
j++
}
else {
k++
}
}
END{
print i "管理员",j "系统用户",k "普通用户"
}
2.打印/etc/passwd文件中UID小于50的、或者UID大于50小于100、或者UID大于100的用户名以及UID。
BEGIN{
FS=":"
printf "%-20s %-20s %-20s \n","UID区间","用户名","UID"
}
{
if($3<50){
i++
printf "%-20s %-20s %-20s \n","UID<50",$1,$3
}
else if($3>50&&$3<100){
j++
printf "%-20s %-20s %-20s \n","50<UID<100",$1,$3
}
else {
k++
printf "%-20s %-20s %-20s \n","100<UID",$1,$3
}
}
END{
print "UID<50 :"i,"50<UID<100 :"j,"100<UID :"k
}
awk循环语句
while循环
while (条件表达式)动作
1.打印1-9
awk 'BEGIN{i=1;while(i<10){print i;i++}}'
2.打印passwd文件的每一行中的每一列
awk -F":" '{i=1;while(i<=NF){print $i;i++}}' passwd
for循环
for(初始化计数器;计数器测试;计数器变更)动作
1.遍历1-4
awk 'BEGIN{for(i=1;i<5;i++){print i}}'
2.每行打印10次
awk -F":" '{for(i=1;i<=10;i++){print $0}}' passwd
3.打印每一行每一列
awk -F":" '{for(i=1;i<=NF;i++){print $i}}' passwd
4.计算1+2+3+4+…+100的和,请使用while、for两种循环方式实现
shell
#!/bin/bash
for i in {1..100}
do
sum=$[$sum+$i] #或 let sum+=i
done
echo $sum
while循环:
awk 'BEGIN{i=1;while(i<=100){sum+=i;i++} {print sum}}'
或
BEGIN{
while (i<=100){
sum+=i
i++
}
print sum
}
for循环:
awk 'BEGIN{for(i=1;i<=100;i++){sum+=i}print sum}'
或
BEGIN{
for(i=1;i<=100;i++){
sum+=i
}
print sum
}