【shell】awk基本用法



一、awk概述与使用场景

  • awk是一种编程语言,主要用于在linux/unix下对文本和数据进行处理,是linux/unix下的一个工具。数据可以来自标准输入、一个或多个文件,或其它命令的输出。

  • awk的处理文本和数据的方式:逐行扫描文件,默认从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行你想要的操作。

  • awk分别代表其作者姓氏的第一个字母。因为它的作者是三个人,分别是Alfred Aho、Brian Kernighan、Peter Weinberger。

  • gawk是awk的GNU版本,它提供了Bell实验室和GNU的一些扩展。

[wqf@b1i10 test]$ which awk
/usr/bin/awk
[wqf@b1i10 test]$ ll /usr/bin/awk
lrwxrwxrwx. 1 root root 4 Sep 21  2021 /usr/bin/awk -> gawk
  • 下面介绍的awk是以GNU的gawk为例的,在linux系统中已把awk链接到gawk,所以下面全部以awk进行介绍。

二、awk使用方式

1、命令行模式使用

语法结构:

awk 选项 '命令部分' 文件名
特别说明:命令部分用单引号,假如我在这个命令部分引用shell变量需用双引号引起 

常用选项:

-F 定义字段分割符号,默认的分隔符是空格
-v 定义变量并赋值

‘命令部分’ 说明:

  • 正则表达式:正则匹配要用//括起来,表示为 /正则表达式/
'/root/{awk语句}'                
'NR==1,NR==5{awk语句}'        
'/^root/,/^ftp/{awk语句}' 
  • {awk语句1; awk语句2;…}
'{print $0;print $1}'  
'NR==5{print $0}' 
注:awk命令语句间用分号间隔
  • BEGIN…END…
    • BEGIN:表示在程序开始前执行
    • END :表示所有文件处理完后执行
'BEGIN{awk语句};{处理中};END{awk语句}' 
'BEGIN{awk语句};{处理中}' 
'{处理中};END{awk语句}'

2、脚本模式使用(awk -f awkScript.sh file)

脚本编写:

#!/bin/awk -f         定义魔法字符
以下是awk引号里的命令清单,不要用引号保护命令,多个命令用分号间隔
BEGIN{
    
    FS=":"}
NR==1,NR==3{
    
    print $1"\t"$NF}

脚本执行:

方法1:
awk 选项 -f awk的脚本文件  要处理的文本文件
awk -f awk.sh filename

sed -f sed.sh -i filename

方法2:
./awk的脚本文件(或者绝对路径)    要处理的文本文件
./awk.sh filename

./sed.sh filename

三、awk内部相关变量

变量 变量说明 备注
$0 当前处理行的所有记录
1,2,3…n 文件中每行以间隔符号分割的不同字段 awk -F: ‘{print 1,3}’
NF 当前记录的字段数(列数) awk -F: ‘{print NF}’
$NF 最后一列 $(NF-1)表示倒数第二列
FNR/NR 行号
FS 定义间隔符 ‘BEGIN{FS=“:”};{print 1,3}’
OFS 定义输出字段分隔符,默认空格 ‘BEGIN{OFS=“\t”};print 1,3}’
RS 输入记录分割符,默认换行 ‘BEGIN{RS=“\t”};{print $0}’
ORS 输出记录分割符,默认换行 ‘BEGIN{ORS=“\n\n”};{print 1,3}’
FILENAME 当前输入的文件名

常用变量分隔符举例

文件准备:

[wqf@b1i10 rm_test]$ cat -n 1.txt
     1  root:x:0:0:root:/roots:/bin/bash
     2  bin:x:1:1:bin:/bins:/sbin/nologin
     3  daemon123:x:2:2:daemon:/sbins:/sbin/nologin
     4  adm:x:3:4:adm:/var/adms:/sbin/nologin
     5  lp:x:4:7:lp:/var/spool/lpds:/sbin/nologin
     6  298374837483
     7  172.16.0.254
     8  10.1.1.1
## 打印所有行数
[wqf@b1i10 rm_test]$ awk '{print $0}' 1.txt 
root:x:0:0:root:/roots:/bin/bash
bin:x:1:1:bin:/bins:/sbin/nologin
daemon123:x:2:2:daemon:/sbins:/sbin/nologin
adm:x:3:4:adm:/var/adms:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpds:/sbin/nologin
298374837483
172.16.0.254
10.1.1.1

## 打印第1行至第5行
[wqf@b1i10 rm_test]$ awk 'NR==1,NR==5{print $0}' 1.txt 
root:x:0:0:root:/roots:/bin/bash
bin:x:1:1:bin:/bins:/sbin/nologin
daemon123:x:2:2:daemon:/sbins:/sbin/nologin
adm:x:3:4:adm:/var/adms:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpds:/sbin/nologin
[wqf@b1i10 rm_test]$ awk 'NR==1||NR==5{print $0}' 1.txt
root:x:0:0:root:/roots:/bin/bash
lp:x:4:7:lp:/var/spool/lpds:/sbin/nologin

## 打印第2行至第5行
[wqf@b1i10 rm_test]$ awk 'NR>=2&&NR<=5{print $0}' 1.txt
bin:x:1:1:bin:/bins:/sbin/nologin
daemon123:x:2:2:daemon:/sbins:/sbin/nologin
adm:x:3:4:adm:/var/adms:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpds:/sbin/nologin

## 打印每一行的第一列和最后一列,用:分隔开。
[wqf@b1i10 rm_test]$ awk -F: '{print $1,$NF}' 1.txt
root /bin/bash
bin /sbin/nologin
daemon123 /sbin/nologin
adm /sbin/nologin
lp /sbin/nologin
298374837483 298374837483
172.16.0.254 172.16.0.254
10.1.1.1 10.1.1.1

## 打印当前所有行的列数(以:为分隔符)
[wqf@b1i10 rm_test]$ awk -F: '{print NF}' 1.txt
7
7
7
7
7
1
1
1

## 打印每一行的第一列和倒数一列,用:分隔开。
[wqf@b1i10 rm_test]$ awk -F: '{print $1,$(NF-1)}' 1.txt
root /roots
bin /bins
daemon123 /sbins
adm /var/adms
lp /var/spool/lpds
298374837483 298374837483
172.16.0.254 172.16.0.254
10.1.1.1 10.1.1.1

## 打印每一行的第一列、倒数一列、最后一列和列数,用:分隔开。
[wqf@b1i10 rm_test]$ awk -F: '{print $1,$(NF-1),$NF,NF}' 1.txt
root /roots /bin/bash 7
bin /bins /sbin/nologin 7
daemon123 /sbins /sbin/nologin 7
adm /var/adms /sbin/nologin 7
lp /var/spool/lpds /sbin/nologin 7
298374837483 298374837483 298374837483 1
172.16.0.254 172.16.0.254 172.16.0.254 1
10.1.1.1 10.1.1.1 10.1.1.1 1

## 打印含有root字符串的行
[wqf@b1i10 rm_test]$ awk '/root/{print $0}' 1.txt
root:x:0:0:root:/roots:/bin/bash

[wqf@b1i10 rm_test]$ awk '/root/' 1.txt
root:x:0:0:root:/roots:/bin/bash

## 打印含有root字符串的行的第一列和最后一列
[wqf@b1i10 rm_test]$ awk -F: '/root/{print $1,$NF}' 1.txt
root /bin/bash

## awk命令语句间用分号间隔
[wqf@b1i10 rm_test]$ awk 'NR==1,NR==5;/^root/{print $0}' 1.txt 
root:x:0:0:root:/roots:/bin/bash ## 符合命令 NR==1,NR==5
root:x:0:0:root:/roots:/bin/bash ## 符合命令 /^root/{print $0}
bin:x:1:1:bin:/bins:/sbin/nologin ## 符合命令 NR==1,NR==5
daemon123:x:2:2:daemon:/sbins:/sbin/nologin ## 符合命令 NR==1,NR==5
adm:x:3:4:adm:/var/adms:/sbin/nologin ## 符合命令 NR==1,NR==5
lp:x:4:7:lp:/var/spool/lpds:/sbin/nologin ## 符合命令 NR==1,NR==5

## ~是匹配 !~不匹配
## 打印第一行至第五行且以root开头的行(输出所有列)
[wqf@b1i10 rm_test]$ awk 'NR>=1 && NR<=5 && $0 ~/^root/{print $0}' 1.txt 
root:x:0:0:root:/roots:/bin/bash        hello   world

## 打印第一行至第五行且不以root开头的行
[wqf@b1i10 rm_test]$ awk 'NR>=1 && NR<=5 && $0 !~/^root/{print $0}' 1.txt 
ibin:x:1:1:bin:/bins:/sbin/nologin      heima
daemon123:x:2:2:daemon:/sbins:/sbin/nologin
adm:x:3:4:adm:/var/adms:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpds:/sbin/nologin

内置变量分隔符举例

FS:读取文件时的列分隔符;OFS:输出文件时的列分隔符

## 默认输出字段分隔符为空格
[wqf@b1i10 rm_test]$ awk -F: '{print $1,$NF}' 1.txt 
root /bin/bash
bin /sbin/nologin
daemon123 /sbin/nologin
adm /sbin/nologin
lp /sbin/nologin
298374837483 298374837483
172.16.0.254 172.16.0.254
10.1.1.1 10.1.1.1

## 定义输出字段分隔符为@@@
[wqf@b1i10 rm_test]$ awk -F: 'BEGIN{OFS="@@@"};{print $1,$NF}' 1.txt
root@@@/bin/bash
bin@@@/sbin/nologin
daemon123@@@/sbin/nologin
adm@@@/sbin/nologin
lp@@@/sbin/nologin
298374837483@@@298374837483
172.16.0.254@@@172.16.0.254
10.1.1.1@@@10.1.1.1

## 定义间隔符为:,输出字段分隔符为@@@
[wqf@b1i10 rm_test]$ awk 'BEGIN{FS=":";OFS="@@@"};{print $1,$NF}' 1.txt
root@@@/bin/bash
bin@@@/sbin/nologin
daemon123@@@/sbin/nologin
adm@@@/sbin/nologin
lp@@@/sbin/nologin
298374837483@@@298374837483
172.16.0.254@@@172.16.0.254
10.1.1.1@@@10.1.1.1

## 可以双引号引用字符串输出
[wqf@b1i10 rm_test]$  awk 'BEGIN{FS=":"};{print $1,"******"$NF}' 1.txt
root ******/bin/bash
bin ******/sbin/nologin
daemon123 ******/sbin/nologin
adm ******/sbin/nologin
lp ******/sbin/nologin
298374837483 ******298374837483
172.16.0.254 ******172.16.0.254
10.1.1.1 ******10.1.1.1

[wqf@b1i10 rm_test]$  awk 'BEGIN{FS=":"};{print "用户名是:"$1,"******解析器:"$NF}' 1.txt
用户名是:root ******解析器:/bin/bash
用户名是:bin ******解析器:/sbin/nologin
用户名是:daemon123 ******解析器:/sbin/nologin
用户名是:adm ******解析器:/sbin/nologin
用户名是:lp ******解析器:/sbin/nologin
用户名是:298374837483 ******解析器:298374837483
用户名是:172.16.0.254 ******解析器:172.16.0.254
用户名是:10.1.1.1 ******解析器:10.1.1.1

RS:读取文件时的行分隔符;ORS:输出文件时的行分隔符

文件准备:修改源文件前2行增加制表符和内容

[wqf@b1i10 rm_test]$ cat 1.txt
root:x:0:0:root:/roots:/bin/bash        hello   world
ibin:x:1:1:bin:/bins:/sbin/nologin      heima
daemon123:x:2:2:daemon:/sbins:/sbin/nologin
adm:x:3:4:adm:/var/adms:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpds:/sbin/nologin
298374837483
172.16.0.254
10.1.1.1
## 读取文件时的行分隔符为制表符\t
[wqf@b1i10 rm_test]$ awk -F: 'BEGIN{RS="\t"};{print $1}' 1.txt
root
hello
world ## world和ibin其实也是同一行,以:分列,取第一列的字段
ibin
heima
daemon123 ## heima和daemon123 其实是同一行,以:分列,取第一列的字段

## 输出文件时的行分隔符为制表符\t
[wqf@b1i10 rm_test]$ awk -F: 'BEGIN{ORS="\t"};{print $1}' 1.txt
root    ibin    daemon123       adm     lp      298374837483    172.16.0.254    10.1.1.1 

四、awk进阶应用

1、格式化输出print和printf举例

%s 字符类型 strings %-20s
%d 数值类型
-  表示左对齐,默认是右对齐
printf 默认不会在行尾自动换行,加\n

print 函数:类似echo “hello world”

[wqf@b1i10 ~]$ date|awk '{print "Month:"$2"\nyear:"$NF}'
Month:May
year:2023

printf 函数:类似echo -n

## 限制字符串长度并且左对齐
[wqf@b1i10 rm_test]$ awk -F: '{printf "%-15s %-10s %-15s\n", $1,$2,$3}'  3.txt
[wqf@b1i10 rm_test]$ awk 'BEGIN{FS=":"};{printf "%-15s %-10s %-15s\n", $1,$2,$3}'  3.txt
root            x          0              
bin             x          1              
daemon          x          2              
adm             x          3              
lp              x          4              
sync            x          5              
shutdown        x          6              
halt            x          7              
mail            x          8              
operator        x          11             
games           x          12             
ftp             x          14             
nobody          x          99             
systemd-network x          192            
dbus            x          81             
polkitd         x          999            
apache          x          48             
unbound         x          998            
libstoragemgmt  x          997            
colord          x          996      

## 限制字符串长度并且加入|      
[wqf@b1i10 rm_test]$ awk -F: '{printf "|%15s| %10s| %15s|\n", $1,$2,$3}' 3.txt
|           root|          x|               0|
|            bin|          x|               1|
|         daemon|          x|               2|
|            adm|          x|               3|
|             lp|          x|               4|
|           sync|          x|               5|
|       shutdown|          x|               6|
|           halt|          x|               7|
|           mail|          x|               8|
|       operator|          x|              11|
|          games|          x|              12|
|            ftp|          x|              14|
|         nobody|          x|              99|
|systemd-network|          x|             192|
|           dbus|          x|              81|
|        polkitd|          x|             999|
|         apache|          x|              48|
|        unbound|          x|             998|
| libstoragemgmt|          x|             997|
|         colord|          x|             996|

## 限制字符串长度并且左对齐,加入|
[wqf@b1i10 rm_test]$ awk -F: '{printf "|%-15s| %-10s| %-15s|\n", $1,$2,$3}' 3.txt
|root           | x         | 0              |
|bin            | x         | 1              |
|daemon         | x         | 2              |
|adm            | x         | 3              |
|lp             | x         | 4              |
|sync           | x         | 5              |
|shutdown       | x         | 6              |
|halt           | x         | 7              |
|mail           | x         | 8              |
|operator       | x         | 11             |
|games          | x         | 12             |
|ftp            | x         | 14             |
|nobody         | x         | 99             |
|systemd-network| x         | 192            |
|dbus           | x         | 81             |
|polkitd        | x         | 999            |
|apache         | x         | 48             |
|unbound        | x         | 998            |
|libstoragemgmt | x         | 997            |
|colord         | x         | 996            |

2、awk变量定义

  • awk中调用定义的变量不需要加$
## 对比可知加入$不能如期赋值变量
[wqf@b1i10 rm_test]$ awk -v NUM=3 -F: '{print $NUM}' 1.txt
0
1
2
3
4




[wqf@b1i10 rm_test]$ awk -v NUM=3 -F: '{print NUM}' 1.txt
3
3
3
3
3
3
3
3

[wqf@b1i10 rm_test]$ awk -v num=1 'BEGIN{print num}' 
1
[wqf@b1i10 rm_test]$ awk -v num=1 'BEGIN{print $num}' 

3、awk中BEGIN…END使用

举例

[wqf@b1i10 rm_test]$ awk -F: 'BEGIN{print "Login_shell\t\tLogin_home\n*******************"};{print $NF"\t\t"$(NF-1)};END{print "************************"}' 3.txt
Login_shell             Login_home
*******************
/bin/bash               /root
/sbin/nologin           /bin
/sbin/nologin           /sbin
/sbin/nologin           /var/adm
/sbin/nologin           /var/spool/lpd
/bin/sync               /sbin
/sbin/shutdown          /sbin
/sbin/halt              /sbin
/sbin/nologin           /var/spool/mail
/sbin/nologin           /root
/sbin/nologin           /usr/games
/sbin/nologin           /var/ftp
/sbin/nologin           /
/sbin/nologin           /
/sbin/nologin           /
/sbin/nologin           /
/sbin/nologin           /usr/share/httpd
/sbin/nologin           /etc/unbound
/sbin/nologin           /var/run/lsm
/sbin/nologin           /var/lib/colord
************************

[wqf@b1i10 rm_test]$ awk 'BEGIN{FS=":";print "Login_shell\tLogin_home\n*******************"};{print $NF"\t"$(NF-1)};END{print "************************"}' 3.txt
Login_shell     Login_home
*******************
/bin/bash       /root
/sbin/nologin   /bin
/sbin/nologin   /sbin
/sbin/nologin   /var/adm
/sbin/nologin   /var/spool/lpd
/bin/sync       /sbin
/sbin/shutdown  /sbin
/sbin/halt      /sbin
/sbin/nologin   /var/spool/mail
/sbin/nologin   /root
/sbin/nologin   /usr/games
/sbin/nologin   /var/ftp
/sbin/nologin   /
/sbin/nologin   /
/sbin/nologin   /
/sbin/nologin   /
/sbin/nologin   /usr/share/httpd
/sbin/nologin   /etc/unbound
/sbin/nologin   /var/run/lsm
/sbin/nologin   /var/lib/colord
************************

[wqf@b1i10 rm_test]$ awk -F: 'BEGIN{OFS="\t\t";print"u_name\t\th_dir\t\tshell\n***************************"};{printf "%-20s %-20s %-20s\n",$1,$(NF-1),$NF};END{print "****************************"}' 3.txt
[wqf@b1i10 rm_test]$ awk -F: 'BEGIN{print "u_name\t\th_dir\t\tshell" RS "*****************"}  {printf "%-15s %-20s %-20s\n",$1,$(NF-1),$NF}END{print "***************************"}' 3.txt
u_name          h_dir           shell
*****************
root            /root                /bin/bash           
bin             /bin                 /sbin/nologin       
daemon          /sbin                /sbin/nologin       
adm             /var/adm             /sbin/nologin       
lp              /var/spool/lpd       /sbin/nologin       
sync            /sbin                /bin/sync           
shutdown        /sbin                /sbin/shutdown      
halt            /sbin                /sbin/halt          
mail            /var/spool/mail      /sbin/nologin       
operator        /root                /sbin/nologin       
games           /usr/games           /sbin/nologin       
ftp             /var/ftp             /sbin/nologin       
nobody          /                    /sbin/nologin       
systemd-network /                    /sbin/nologin       
dbus            /                    /sbin/nologin       
polkitd         /                    /sbin/nologin       
apache          /usr/share/httpd     /sbin/nologin       
unbound         /etc/unbound         /sbin/nologin       
libstoragemgmt  /var/run/lsm         /sbin/nologin       
colord          /var/lib/colord      /sbin/nologin       
***************************

4、awk和正则的综合运用

运算符 说明
== 等于
!= 不等于
> 大于
< 小于
>= 大于等于
<= 小于等于
~ 匹配
!~ 不匹配
! 逻辑非
&& 逻辑与
\ \

举例

## 打印 从第一行开始匹配到以lp开头行
[wqf@b1i10 rm_test]$ awk -F: 'NR==1,/^lp/{print $0}' 1.txt
root:x:0:0:root:/roots:/bin/bash        hello   world
ibin:x:1:1:bin:/bins:/sbin/nologin      heima
daemon123:x:2:2:daemon:/sbins:/sbin/nologin
adm:x:3:4:adm:/var/adms:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpds:/sbin/nologin

## 打印 从第一行到第5行          
[wqf@b1i10 rm_test]$ awk -F: 'NR==1,NR==5{print $0}'  1.txt
root:x:0:0:root:/roots:/bin/bash        hello   world
ibin:x:1:1:bin:/bins:/sbin/nologin      heima
daemon123:x:2:2:daemon:/sbins:/sbin/nologin
adm:x:3:4:adm:/var/adms:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpds:/sbin/nologin

## 打印 从lp开头的行匹配到第10行 
[wqf@b1i10 rm_test]$ awk -F: '/^lp/,NR==10{print $0}' 1.txt
lp:x:4:7:lp:/var/spool/lpds:/sbin/nologin
298374837483
172.16.0.254
10.1.1.1

## 打印 从root开头的行匹配到以lp开头的行       
[wqf@b1i10 rm_test]$ awk -F: '/^root/,/^lp/{print $0}' 1.txt
root:x:0:0:root:/roots:/bin/bash        hello   world
ibin:x:1:1:bin:/bins:/sbin/nologin      heima
daemon123:x:2:2:daemon:/sbins:/sbin/nologin
adm:x:3:4:adm:/var/adms:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpds:/sbin/nologin


## 打印 以root开头或者以lp开头的行            
[wqf@b1i10 rm_test]$ awk -F: '/^root/ || /^lp/{print $0}' 1.txt
root:x:0:0:root:/roots:/bin/bash        hello   world
lp:x:4:7:lp:/var/spool/lpds:/sbin/nologin

[wqf@b1i10 rm_test]$ awk -F: '/^root/;/^lp/{print $0}' 1.txt
root:x:0:0:root:/roots:/bin/bash        hello   world
lp:x:4:7:lp:/var/spool/lpds:/sbin/nologin

## 打印以root开头的第三列(以:为分隔符)或者以lp开头的行 
[wqf@b1i10 rm_test]$ awk -F: '/^root/{print $1};/^lp/{print $0}' 1.txt
root
lp:x:4:7:lp:/var/spool/lpds:/sbin/nologin

## 显示5-10行   
[wqf@b1i10 rm_test]$ awk -F':' 'NR>=5 && NR<=10 {print $0}' 3.txt  
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin 

##打印1-39行且第一列开始匹配以bash结尾的内容,输出整行(当前行所有的列)
[wqf@b1i10 rm_test]$ awk 'NR>=1 && NR<=39 && $0 ~ /bash$/{print $0}' 2.txt
root:x:0:0:root:/root:/bin/bash

##打印1-5行以root开头的内容
[wqf@b1i10 rm_test]$ awk 'NR>=1 && NR<=5 && $0 ~ /^root/{print $0}' 1.txt
root:x:0:0:root:/roots:/bin/bash        hello   world

## 打印文件中1-5并且不以root开头的行
[wqf@b1i10 rm_test]$ awk 'NR>=1 && NR<=5 && $0 !~ /^root/{print $0}' 1.txt
ibin:x:1:1:bin:/bins:/sbin/nologin      heima
daemon123:x:2:2:daemon:/sbins:/sbin/nologin
adm:x:3:4:adm:/var/adms:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpds:/sbin/nologin

## 打印以bash结尾的行
[wqf@b1i10 rm_test]$ awk '/bash$/{print $0}'    3.txt
root:x:0:0:root:/root:/bin/bash

[wqf@b1i10 rm_test]$ awk '/bash$/' 3.txt
root:x:0:0:root:/root:/bin/bash

## 从第7列匹配以bash结尾,输出整行(当前行所有的列)
[wqf@b1i10 rm_test]$ awk -F: '$7 ~ /bash/' 1.txt
root:x:0:0:root:/roots:/bin/bash

## 打印可以登录系统的用户名
[wqf@b1i10 rm_test]$ awk -F: '$0 ~ /\/bin\/bash/{print $1}' 1.txt
root

理解;号和||的含义:

[wqf@b1i10 rm_test]$ awk 'NR>=3 && NR<=8 ; /bash$/' 1.txt
root:x:0:0:root:/roots:/bin/bash
daemon123:x:2:2:daemon:/sbins:/sbin/nologin
adm:x:3:4:adm:/var/adms:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpds:/sbin/nologin
298374837483
172.16.0.254
10.1.1.1

[wqf@b1i10 rm_test]$ awk 'NR>=3 && NR<=8 || /bash$/' 1.txt
root:x:0:0:root:/roots:/bin/bash
daemon123:x:2:2:daemon:/sbins:/sbin/nologin
adm:x:3:4:adm:/var/adms:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpds:/sbin/nologin
298374837483
172.16.0.254
10.1.1.1

5、awk的脚本编程

1)流程控制语句
a)if 结构

语法结构:

if语句:

if [ xxx ];then
xxx
fi

awk 选项 '正则,地址定位{ if(表达式){语句1;语句2;...}}'  文件名

举例:

[wqf@b1i10 rm_test]$ awk -F: '{if($3>=500 && $3<=60000) {print $1,$3}}' 3.txt
polkitd 999
unbound 998
libstoragemgmt 997
colord 996

[wqf@b1i10 rm_test]$  awk -F: '{if($3==0) {print $1"是管理员"}}' 3.txt
root是管理员

[wqf@b1i10 rm_test]$ awk 'BEGIN{if('$(id -u)'==0) {print "admin"}}' 

b)if…else 结构

语法结构:

if...else语句:
if [ xxx ];then
    xxxxx

else
    xxx
fi

awk 选项 '正则,地址定位 {if(表达式){语句;语句;...}else{语句;语句;...}}'  

举例:

[wqf@b1i10 rm_test]$ awk -F: '{if($3>=500 && $3 != 65534) {print $1"是普通用户"} else {print $1,"不是普通用户"}}' 3.txt 
root 不是普通用户
bin 不是普通用户
daemon 不是普通用户
adm 不是普通用户
lp 不是普通用户
sync 不是普通用户
shutdown 不是普通用户
halt 不是普通用户
mail 不是普通用户
operator 不是普通用户
games 不是普通用户
ftp 不是普通用户
nobody 不是普通用户
systemd-network 不是普通用户
dbus 不是普通用户
polkitd是普通用户
apache 不是普通用户
unbound是普通用户
libstoragemgmt是普通用户
colord是普通用户

[wqf@b1i10 rm_test]$ awk 'BEGIN{if( '$(id -u)'>=500 && '$(id -u)' !=65534 ) {print "是普通用户"} else {print "不是普通用户"}}'
是普通用户

c)if…elif…else 结构

语法结构:

if...elif...else语句:
if [xxxx];then
    xxxx
elif [xxx];then
    xxx
....
else
...
fi

awk 选项 '正则,地址定位 { if(表达式1){语句;语句;...}else if(表达式2){语句;语句;...}else if(表达式3){语句;语句;...}else{语句;语句;...}}'  

举例:

[wqf@b1i10 rm_test]$ awk -F: '{ if($3==0) {print $1,":是管理员"} else if($3>=1 && $3<=499 || $3==65534 ) {print $1,":是 系统用户"} else {print $1,":是普通用户"}}' 3.txt
root :是管理员
bin :是系统用户
daemon :是系统用户
adm :是系统用户
lp :是系统用户
sync :是系统用户
shutdown :是系统用户
halt :是系统用户
mail :是系统用户
operator :是系统用户
games :是系统用户
ftp :是系统用户
nobody :是系统用户
systemd-network :是系统用户
dbus :是系统用户
polkitd :是普通用户
apache :是系统用户
unbound :是普通用户
libstoragemgmt :是普通用户
colord :是普通用户


[wqf@b1i10 rm_test]$  awk -F: '{if($3==0) {i++} else if($3>=1 && $3<=499 || $3==65534 ) {j++} else {k++}};END{print "管 理员个数为:"i "\n系统用户个数为:"j"\n普通用户的个数为:"k }' 3.txt
管理员个数为:1
系统用户个数为:15
普通用户的个数为:4


[wqf@b1i10 rm_test]$ awk -F: '{if($3==0){i++} else if($3>999){k++} else{j++}} END{print "管理员个数: "i; print "普通用个数: "k; print "系统用户: "j}' /etc/passwd 
管理员个数: 1
普通用个数: 134
系统用户: 45 

## 如果是普通用户打印默认shell,如果是系统用户打印用户名
[wqf@b1i10 rm_test]$ awk -F: '{if($3>=1 && $3<500 || $3 == 65534) {print $1} else if($3>=500 && $3<=60000 ) {print $NF}}' /etc/passwd

2)循环语句
a)for循环

for ((i=1;i<=5;i++));do echo $i;done

## 打印1~5
[wqf@b1i10 rm_test]$ awk 'BEGIN {for(i=1;i<=5;i++) {print i}}'
1
2
3
4
5

## 求1~10中的奇数和
[wqf@b1i10 rm_test]$ for ((i=1;i<=10;i+=2));do echo $i;done|awk '{sum+=$0};END{print sum}'
25

## 打印1~10中的奇数
[wqf@b1i10 rm_test]$ awk 'BEGIN{for(i=1;i<=10;i+=2) {print i}}'
[wqf@b1i10 rm_test]$ awk 'BEGIN{for(i=1;i<=10;i+=2) print i}'
1
3
5
7
9

## 计算1-5的和
[wqf@b1i10 rm_test]$ awk 'BEGIN{sum=0;for(i=1;i<=5;i++) sum+=i;print sum}'
[wqf@b1i10 rm_test]$ awk 'BEGIN{for(i=1;i<=5;i++) (sum+=i);{print sum}}'
[wqf@b1i10 rm_test]$ awk 'BEGIN{for(i=1;i<=5;i++) (sum+=i);print sum}'
15

b)while循环

## 计算1-5的和
[wqf@b1i10 rm_test]$ awk 'BEGIN{i=1;while(i<=5) {print i;i++}}'
1
2
3
4
5

## 打印1~10中的奇数
[wqf@b1i10 rm_test]$ awk 'BEGIN{i=1;while(i<=10) {print i;i+=2}}'
1
3
5
7
9

## 计算1-5的和
[wqf@b1i10 rm_test]$ awk 'BEGIN{i=1;sum=0;while(i<=5) {sum+=i;i++}; print sum}'
[wqf@b1i10 rm_test]$ awk 'BEGIN{i=1;while(i<=5) {(sum+=i) i++};print sum}'
15

c)嵌套循环

#!/bin/bash
for ((y=1;y<=5;y++))
do
    for ((x=1;x<=$y;x++))
    do
        echo -n $x    
    done
echo
done

[wqf@b1i10 ~]$ awk 'BEGIN {for(y=1;y<=5;y++) { for(x=1;x<=y;x++) {printf x};print}}'
[wqf@b1i10 ~]$ awk 'BEGIN {y=1;while(y<=5) { for(x=1;x<=y;x++) {printf x};y++;print}}'
1
12
123
1234
12345

6、awk算数运算

运算符号

+ - * / %(模) ^(幂2^3)

举例:

[wqf@b1i10 ~]$ awk 'BEGIN{print 1+1}'
2
[wqf@b1i10 ~]$ awk 'BEGIN{print 2**3}'
8
[wqf@b1i10 ~]$ awk 'BEGIN{print 2/3}'
0.666667

五、awk实际情况应用

1)判断号码不被命中的原因

需求说明

文件是针对号码话单进行统计后的结果,提取每列字段对应其统计含义,判断哪一个条件不满足导致此号码没有被命中。

文件准备

[wqf@b1i10 data_val]$ cat test_result.log
130****3963|0752|12|1.2|0.5833333333333334|0.5833333333333334|27|0.31|0|130****3963

实现过程
1、先用 print函数或者 printf函数将每个字段意思打印出来,printf函数打印结果可以调整输出格式。

##printf函数
[wqf@b1i10 ~]$ filename=/apps/wqf/cdc_model/bin/data_val/ test_result.log
[wqf@b1i10 ~]$ calling_num=`awk -F"|" '{printf "%-10s\t%-10s\n","号码:"$1, "主叫次数:"$3}' $filename`
[wqf@b1i10 ~]$ calling_hour_num=`awk -F"|" '{printf "%-10s\t%-10s\n","号码:"$1,  "某1小时内是否大于15次主叫次数:"$9}' $filename`
[wqf@b1i10 ~]$ called_dispersion_rate=`awk -F"|" '{printf "%-10s\t%-10s\n","号码:"$1 , " 被叫离散率:"$4}' $filename`
[wqf@b1i10 ~]$ calling_called_area_same_rate=`awk -F"|" '{printf "%-10s\t%-10s\n","号码:"$1,  " 被叫号码与主叫号码同归属地相同的发呼占比:"$5}' $filename`
[wqf@b1i10 ~]$ calling_visit_area_same_rate=`awk -F"|" '{printf "%-10s\t%-10s\n","号码:"$1, " 被叫号码与主叫号码发呼地相同的发呼占比:"$6}' $filename`
[wqf@b1i10 ~]$ calling_rate=`awk -F"|" '{printf "%-10s\t%-10s\n","号码:"$1," 主叫占比:"$8}' $filename`
[wqf@b1i10 ~]$ whether_calling=`awk -F"|" '{printf "%-10s\t%-10s\n","号码:"$1,"06:00-9:00是否有主叫通话记录:"$10}' $filename`

##print函数
[wqf@b1i10 ~]$ calling_num=`awk -F"|" '{print "号码:"$1, "主叫次数:" $3}' $filename`
[wqf@b1i10 ~]$ calling_hour_num=`awk -F"|" '{print "号码:"$1 ,"某1小时内是否大于15次主叫次数:" $9}' $filename`
[wqf@b1i10 ~]$ called_dispersion_rate=`awk -F"|" '{print "号码:"$1 ," 被叫离散率:" $4}' $filename`
[wqf@b1i10 ~]$ calling_called_area_same_rate=`awk -F"|" '{print "号码:"$1, " 被叫号码与主叫号码同归属地相同的发呼占比:" $5}' $filename`
[wqf@b1i10 ~]$ calling_visit_area_same_rate=`awk -F"|" '{print "号码:"$1 ," 被叫号码与主叫号码发呼地相同的发呼占比:" $6}' $filename`
[wqf@b1i10 ~]$ calling_rate=`awk -F"|" '{print "号码:"$1, " 主叫占比:" $8}' $filename`
[wqf@b1i10 ~]$ whether_calling=`awk -F"|" '{print "号码:"$1 ," 06:00-9:00是否有主叫通话记录:" $10}' $filename`

[wqf@b1i10 ~]$ echo -e $calling_num"\n"$calling_hour_num"\n"$called_dispersion_rate"\n"$calling_called_area_same_rate"\n"$calling_visit_area_same_rate"\n"$calling_rate"\n"$whether_calling
号码:130****3963 主叫次数:12 
号码:130****3963 某1小时内是否大于15次主叫次数:0
号码:130****3963 被叫离散率:1.2
号码:130****3963 被叫号码与主叫号码同归属地相同的发呼占比:0.5833333333333334
号码:130****3963 被叫号码与主叫号码发呼地相同的发呼占比:0.5833333333333334
号码:130****3963 主叫占比:0.31
号码:130****3963 06:00-9:00是否有主叫通话记录:130****3963

2、awk 嵌套 if…elif…else 结构判断哪个条件不满足

[wqf@b1i10 data_val]$ awk 'BEGIN{FS="|"} {if ($3<30 || $4>=1.3) {printf "%-10s\t%-10s\t%-10s\n","主叫次数:"$3,"被叫离散 率:"$4,$1"不满足主叫次数>=30且被叫离散率<1.3"} else if($9!=15 || $4>=1.3) {printf "%-10s\t%-10s\n%-10s\n","某1小时内,主叫次数是否>=15:"$9,"被叫离散率:"$4,$1":不满足规则:某1小时内,主叫次数>=15且被叫离散率<1.2"} else if($5>0.3) {printf "%-10s\n%-10s\n","被叫号码与主叫号码同归属地相同的发呼占比:"$5,$1":不满足被叫号码与主叫号码同归属地相同的发呼占比<=30%"} else if($6>0.3) {printf "%-10s\n%-10s\n","被叫号码与主叫号码发呼地相同的发呼占比:"$6,$1":不满足被叫号码与主叫号码发呼地相同的发呼占比<=30%"}  else if($7<0.9) {printf "%-10s\n%-10s\n"," 主叫占比:"$7,$1":不满足主叫占比>=90%"}}'  test_result.log

2)查找第二列大于0.97的所有行,查看号码量

文件准备

[wwqf@b1i10 result_data]$ head result_20230319_1.txt
neg     pos     calling_nbr     res
0.0023  0.9977  13302873173     1
0.041   0.959   13310815518     1
0.0286  0.9714  13316151376     1
0.0485  0.9515  13316270892     1
0.0083  0.9917  13316593420     1
0.0159  0.9841  13316765627     1
0.0399  0.9601  13318208857     1
0.0261  0.9739  13318445264     1
0.0172  0.9828  13318611412     1

实现过程

[wqf@b1i10 result_data]$ awk -F ' ' '$2>0.97{print $0}' result_20230319_1.txt | wc -l
6883

3)查看表占用空间大小

方法1:
1、查看hive表的字段信息及元数据存储路径

desc formatted table_name;
--查看Location:对应的路径信息为 hive表存储路径

2、 查看文件空间大小 hadoop fs -du 表存储路径,下面例子只截取一部分信息,第1列表下面文件是占用容量大小

[wqf@b1i10 ~]$ hadoop fs -du hdfs://b1/apps/wqf/hive/wqf/cdc_black_history_chaiji_user_list_info
31852445  95557335  hdfs://b1/apps/wqf/hive/wqf/cdc_v1_6_501_all_sample_feature_2023031922/000000_0
31837999  95513997  hdfs://b1/apps/wqf/hive/wqf/cdc_v1_6_501_all_sample_feature_2023031922/000001_0

2、查看该hive表的总容量大小,单位为G

[wqf@b1i10 ~]$ hadoop fs -du hdfs://b1/apps/wqf/hive/wqf/cdc_black_history_chaiji_user_list_info |awk '{SUM += $1} END{print SUM/(1024*1024*1024)”G“}'
1.03685G

方法2:

1、先找到要查询表的存储路径,方法可参考方法1的查询方法。
2、查看文件空间大小 hadoop fs -ls 表存储路径,下面例子只截取一部分信息,第5列表下面文件是占用容量大小

[wqf@b1i10 ~]$ hadoop fs -ls hdfs://b1/apps/wqf/hive/wqf/cdc_black_history_chaiji_user_list_info
-rw-r--r--   3 wqf wqf 31852445 2023-03-24 17:01 hdfs://b1/apps/wqf/hive/wqf/cdc_v1_6_501_all_sample_feature_2023031922/000000_0
-rw-r--r--   3 wqf wqf 31837999 2023-03-24 17:01 hdfs://b1/apps/wqf/hive/wqf/cdc_v1_6_501_all_sample_feature_2023031922/000001_0

3、查看该hive普通表总容量大小,单位为G

[wqf@b1i10 ~]$ hadoop fs -ls hdfs://b1/apps/wqf/hive/wqf/cdc_v1_6_501_all_sample_feature_2023031922 | awk -F' ' '{SUM+=$5}END {print SUM/(1024*1024*1024)"G"}'
[wqf@b1i10 ~]$ hadoop fs -ls hdfs://b1/apps/wqf/hive/wqf/cdc_v1_6_501_all_sample_feature_2023031922 | awk -F ' ' '{print $5}'|awk '{a+=$1}END {print a/(1024*1024*1024)"G"}'
1.03685G

猜你喜欢

转载自blog.csdn.net/sodaloveer/article/details/130499353
今日推荐