Linux基础之三剑客AWK基础篇

awk介绍

  • AWK是一种优良的文本处理工具,Linux及Unix环境中现有的功能最强大的数据处理引擎之一
  • 这种编程及数据操作语言(其名称得自于它的创始人阿尔佛雷德·艾侯、彼得·温伯格和布莱恩·柯林汉姓氏的首个字母)的最大功能取决于一个人所拥有的知识
  • AWK(Aho、Weinberger、Kernighan) ,报告生成器,简单的来说就是打报表,格式化文本输出
  • 它具备了一个完整的语言所应具有的几乎所有精美特性
  • 实际上AWK的确拥有自己的语言:AWK程序设计语言,三位创建者已将它正式定义为“样式扫描和处理语言”
  • AWK版本还特别多;New AWK (nawk), GNU AWK (gawk),当然我们用的是GAWK,属于GNU项目

awk基本用法

  • awk报告生成器,格式化输出文本文件

  • awk基本语法格式

    • awk [options] ‘program’ var=value file…
    • awk [options] -f programfile var=value file…
    • awk [options] 'BEGIN{ action;… } pattern{ action;… } END
    • action;… }' file ...
  • optinos 表示可选的命令行选项

  • prgoramawk语句

  • var=value自己定义变量

  • file.... 处理文本文件

  • programfile 调用程序文件

  • program通常是被单引号或双引号中,建议用单引号,双引号在后面有其他用途

  • awk程序

    • awk 程序通常由:BEGIN语句块、能够使用模式匹配的通用语句块、END语句块,共3部分组成
  • awk选项

    • -F: 指明输入时用到的字段分隔符
[root@localhost ~]# awk -F: '{print $1}' /etc/passwd
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator
games
ftp
nobody
systemd-bus-proxy
systemd-network
dbus
polkitd
colord
abrt
libstoragemgmt
rpc
 -  -v :var=value: 自定义变量
[root@localhost ~]# awk -v RS=':' '{print }'  /etc/passwd
root
x
0
0
root
/root
/bin/bash
bin
x
1
1
bin
/bin
/sbin/nologin
daemon
x
2
2
daemon
/sbin

awk语言

  • 基本格式:awk [options] 'program' file…
  • program:pattern{action statements;..}
  • pattern和action:
    • pattern:部分决定动作语句何时触发及触发事件
    • BEGIN:相当于处理文件内容之前执行的一个语句,用于打印标题
    • END:
      • action statements:对数据进行处理,如统计、汇总等
  • 分割符、域和记录
  • awk在执行时,由分割符来分割字段,可以用冒号或者斜线等等要看自己的指定
  • 切割完已后那就是一个字段,可以说是局部变量$1$2...... 用awk自己来调用,不用自己声明,有一个需要注意$0就是所有字段或所有列
  • 选项-F就是用来指定分割符的
  • 域的意思就是已经被切割完的字符,也可以称呼为列或字段等,比如说第一行就用$1他会把一列全打印显示处理
  • 记录就是说一行就是一条记录,怎么去区分行一行或几行,那就是分割符,分割符要看自己来指定千万别记太死
  • 默认空格为换行符,但是其他的换行符需要自己指定

awk工作原理

  • 第一步:执行BEGIN{action;… }语句块中的语句
  • 第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ action;… }语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕
  • 第三步:当读至输入流末尾时,执行END{action;…}语句块
  • BEGIN:这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句
  • END: 这也是一个科学的语句块,比如打印所有行的分析结果等信息汇总或awk输入流读取完所有信息将会执行END
  • pattern语句块中的通用命令是最重要的部分,也是可选的。如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取到的行,awk读取的每一行都会执行该语句块

print

  • AWK是默认读取标准输入的命令

  • 读取多少行就打印多少行,用文件输入或手动输入都可以

  • 要点:

    • 逗号分隔符
    • 输出的各item可以字符串,也可以是数值;当前记录的字段、变量或awk的表达式
    • 如省略item,相当于print $0
  • 示例

    [root@localhost ~]# awk '{print "hello,awk"}' /etc/passwd
hello,awk
hello,awk
hello,awk
hello,awk
hello,awk
hello,awk
hello,awk
hello,awk
  • 在输出的时候,打印的内容必须要以,号隔开不然会合并在一起
[root@localhost ~]# awk -F: '{print $1$4}' /etc/passwd 
root0
bin1
daemon2
adm4
lp7
sync0
shutdown0
halt0
mail12
operator0
games100
ftp50
nobody99
systemd-bus-proxy997
systemd-network192
dbus81
polkitd996
colord995
abrt173
  • 如果用,号将会分割开
[root@localhost ~]# awk -F: '{print $1,$4}' /etc/passwd 
root 0
bin 1
daemon 2
adm 4
lp 7
sync 0
shutdown 0
halt 0
mail 12
operator 0
games 100
ftp 50
nobody 99
systemd-bus-proxy 997
systemd-network 192
dbus 81
polkitd 996
colord 995
abrt 173
  • 如果你想用别的符号来分割你可以补上,中间加的是字符串哦,别搞混了
[root@localhost ~]# awk -F: '{print $1"===="$4}' /etc/passwd 
root====0
bin====1
daemon====2
adm====4
lp====7
sync====0
shutdown====0
halt====0
mail====12
operator====0
games====100
ftp====50
nobody====99
systemd-bus-proxy====997
systemd-network====192
dbus====81
polkitd====996
colord====995
abrt====173
  • 注意我们现在用的是变量不用加双引号,如果是字符串必须要加双引号,不然会这样
[root@localhost ~]# awk -F: '{print $1====$4}' /etc/passwd  
awk: cmd. line:1: {print $1====$4}
awk: cmd. line:1:            ^ syntax error
  • 那如果我想取磁盘利于分区利用率怎么取,可以这样
[root@localhost ~]# df
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/sda2       41922560  385320  41537240   1% /
devtmpfs         2008832       0   2008832   0% /dev
tmpfs            2023456       0   2023456   0% /dev/shm
tmpfs            2023456    8772   2014684   1% /run
tmpfs            2023456       0   2023456   0% /sys/fs/cgroup
/dev/sda3       20961280 2679012  18282268  13% /usr
/dev/sda1         508580  148756    359824  30% /boot
tmpfs             404692       0    404692   0% /run/user/0
[root@localhost ~]# df|awk '{print $5}'
Use%
1%
0%
0%
1%
0%
13%
30%
0%
  • 如果我只想要数值,不想要符号,或我只想要分区的数值,怎么取,我们可以配合grep
[root@localhost ~]# df|grep '^/dev/sd'|awk '{print $5}'|awk -F% '{print $1 }'
1
13
30
  • 如果你什么都不写会产生什么后果,那就相当打印$0
[root@localhost ~]# awk '{print }' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
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
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
  • 格式输出的时候变量一定要一个一个的打印如
[root@localhost ~]# awk -F: '{print $1,$5,$3}' /etc/passwd
root root 0
bin bin 1
daemon daemon 2
adm adm 3
lp lp 4
sync sync 5
shutdown shutdown 6
halt halt 7
mail mail 8
operator operator 11
games games 12
ftp FTP User 14
nobody Nobody 99
  • 不能这样填写变量
[root@localhost ~]# awk -F: '{print $1-3}' /etc/passwd     
-3
-3
-3
-3
-3
-3
-3
-3
-3
-3
-3
-3
-3
  • 如果你想对其你可以加一个或多个TAB键,但是他是个字符串必须要加双引号
[root@localhost ~]# awk -F: '{print $1"\t\t\t"$3}' /etc/passwd
root                    0
bin                     1
daemon                  2
adm                     3
lp                      4
sync                    5

awk变量

  • 在awk里面也支持内置变量和自定义变量

内置变量

  • 内置变量
  • FS:输入字段分割符,默认为空白字符
  • FS是个变量需要赋值,功能和-F一样
[root@localhost ~]# awk -v FS=: '{print $1}' /etc/passwd
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator
games
ftp
nobody
  • 还可以引用变量
[root@localhost ~]# awk -v FS=':' '{print $1,FS,$3}' /etc/passwd
root : 0
bin : 1
daemon : 2
adm : 3
lp : 4
sync : 5
shutdown : 6
halt : 7
mail : 8
operator : 11
games : 12
ftp : 14
nobody : 99
  • OFS:输出字段分割符,默认为空白字符
[root@localhost ~]# awk -F: -v OFS='-' '{print $1,$3}' /etc/passwd    
root-0
bin-1
daemon-2
adm-3
lp-4
sync-5
shutdown-6
halt-7
mail-8
operator-11
games-12
ftp-14
  • RS:输入记录分割符,指定输入时的换行符,原换行符仍有效
[root@localhost ~]# awk -v RS=' ' '{print }' /etc/passwd 
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
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
  • ORS:输出记录分隔符,输出时用指定符号代替换行符
[root@localhost ~]# awk -F: -v ORS="---" '{print $1}' /etc/passwd 
root---bin---daemon---adm---lp---sync---shutdown---halt---mail---operator---games---ftp---nobody---systemd-bus-proxy---systemd-network---dbus---polkitd---colord---abrt---libstoragemgmt---rpc---setroubleshoot---rtkit---usbmuxd---tss---geoclue---chrony---mysql---pulse---gdm---rpcuser---nfsnobody---postfix---ntp---ssh
  • NF:字段数量,表示一共有7个字段
[root@localhost ~]# awk -F: 'END{print NF}' /etc/passwd   
7
  • NR :行号
[root@localhost ~]# awk -F: '{print NR,$1}'  /etc/passwd
1 root
2 bin
3 daemon
4 adm
5 lp
6 sync
7 shutdown
8 halt
9 mail
10 operator
11 games
12 ftp
13 nobody
14 systemd-bus-proxy
15 systemd-network
16 dbus
17 polkitd
18 colord
19 abrt
  • FNR: 各个文件分别计数,行号
[root@localhost ~]# awk '{print FNR,$0}' /etc/issue  /etc/fstab 
1 \S
2 Kernel \r on an \m
3 
4 Mage Education Learning Services
5 http://www.magedu.com
6 
1 
2 #
3 # /etc/fstab
4 # Created by anaconda on Thu Jul 13 08:26:25 2017
5 #
6 # Accessible filesystems, by reference, are maintained under '/dev/disk'
7 # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
8 #
  • FILENAME:当前文件名
[root@localhost ~]# awk -F: '{print FILENAME,$0}' /etc/issue
/etc/issue \S
/etc/issue Kernel \r on an \m
/etc/issue 
/etc/issue Mage Education Learning Services
/etc/issue http://www.magedu.com
/etc/issue 
  • ARGC:命令行参数的个数
[root@localhost ~]# awk -F: '{print ARGC}'  /etc/passwd /etc/issue /etc/fstab 
4
4
4
4
4
4
4
4
4
  • ARGV:数组,保存的是命令行所给定的各参数
[root@localhost ~]# awk -F: '{print ARGC,ARGV[0]}'  /etc/passwd /etc/issue /etc/fstab  
4 awk
4 awk
4 awk
4 awk
4 awk
4 awk
4 awk
4 awk
4 awk
4 awk
4 awk
4 awk
4 awk
变量名 属性
$0 当前记录
$1~$n 当前记录的第n个字段
FS 输入只读分割符 默认的是空格
RS 输入记录分割符 默认为换行符
NF 当前记录中的字段个数,就是有多少列
NR 已经独处的记录数,就是行号,从1开始
OFS 输出字段分割符 默认也是空格
ORS 输出的记录分割符 默认为换行符
FNR 分别计数
FILENAME 显示当前文件名
ARGC 显示参数个数
ARGV 打印数组参数

注:内置变量很多,参阅相关资料

自定义变量

  • 自定义变量(区分字符大小写)
    • -v var=value
    • 在program中直接定义
  • 示例
[root@localhost ~]# awk -v name=root '{print name}' /etc/passwd  
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
  • 变量调取还可以这样
[root@localhost ~]# awk '{sex="male";print sex }'  /etc/passwd
male
male
male
male
male
male
male
male
male
male
male
male
male
male
male
  • 还可以把他写成一个脚本如
[root@localhost ~]# vi f1.awk 
 {sex="male";print sex}  
~                                                                 
~                                                                 
  • 把他显示调取出来,但是要记住在里面不要放单引号不然出错
[root@localhost ~]# awk -f  f1.awk /etc/passwd
male
male
male
male
male
male
male
male
male
male
male

printf

  • 格式化输出:printf “FORMAT”, item1, item2, ...
  • 必须指定FORMAT, 也就是格式
  • 不会自动换行,需要显式给出换行控制符,\n
  • FORMAT中需要分别为后面每个item指定格式符
  • 格式符:与item一一对应
输出控制符 含义
%C 显示字符的ASCII码
%d,%i 显示十进制整数
%e ,%E 显示科学计数法数值
%f 显示为浮点数
%g ,%G 以科学计数法或浮点形式显示数值
%s 显示字符串
%u 无符号整数
%% 显示%自身
  • 修饰符:
    -#[.#]:第一个数字控制显示的宽度;第二个#表示小数点后精度,%3.1f
    • -: 左对齐(默认右对齐) %-15s
    • +:显示数值的正负符号 %+d
  • 示例
[root@localhost ~]# awk -F: '{printf "%s---%d\n", $1,$3}'  /etc/passwd
root---0
bin---1
daemon---2
adm---3
lp---4
sync---5
shutdown---6
halt---7
mail---8
operator---11
games---12
ftp---14
nobody---99
systemd-bus-proxy---999
systemd-network---192
dbus---81
  • 如果你想右对齐可以这样,因为默认是右对齐
[root@localhost ~]# awk -F: '{printf "%s---%d\n", $1,$3}'  /etc/passwd
root---0
bin---1
daemon---2
adm---3
lp---4
sync---5
shutdown---6
halt---7
mail---8
operator---11
games---12
ftp---14
nobody---99
systemd-bus-proxy---999
systemd-network---192
dbus---81
  • 如果你想左对齐,可以这样
[root@localhost ~]# awk -F: '{printf "%-30s---%d\n", $1,$3}'  /etc/passwd
root                          ---0
bin                           ---1
daemon                        ---2
adm                           ---3
lp                            ---4
sync                          ---5
shutdown                      ---6
halt                          ---7
mail                          ---8
operator                      ---11
games                         ---12
ftp                           ---14
nobody                        ---99
systemd-bus-proxy             ---999
systemd-network               ---192
  • 还可以这样玩,反正自己看着玩
[root@localhost ~]# awk -F: '{printf "%+30s---%+30d\n", $1,$3}'  /etc/passwd
                          root---                            +0
                           bin---                            +1
                        daemon---                            +2
                           adm---                            +3
                            lp---                            +4
                          sync---                            +5
                      shutdown---                            +6
                          halt---                            +7
                          mail---                            +8
                      operator---                           +11
                         games---                           +12
  • 还可以添加字符串,是里面不是外面注意
[root@localhost ~]# awk -F: '{printf "username:%-30s%-10d\n", $1,$3}'  /etc/passwd
username:root                          0         
username:bin                           1         
username:daemon                        2         
username:adm                           3         
username:lp                            4         
username:sync                          5         
username:shutdown                      6         
username:halt                          7         
username:mail                          8         
username:operator                      11        
username:games                         12        
username:ftp                           14        
username:nobody                        99        
username:systemd-bus-proxy             999       
username:systemd-network               192       
username:dbus                          81        

操作符

  • 算术操作符:
    • x+y, x-y, x*y, x/y, x^y, x%y
    • -x: 转换为负数
    • +x: 转换为数值
  • 字符串操作符:没有符号的操作符,字符串连接
  • 赋值操作符:
  • =, +=, -=, *=, /=, %=, ^=
  • ++, --
  • 比较操作符:
  • ==, !=, >, >=, <, <=
  • 模式匹配符:~:左边是否和右边匹配包含 !~:是否不匹配
  • 示例
  • 下面的意思是如果$0包含root就打印,没有就不打印
[root@localhost ~]# awk -F: '$0 ~ /root/{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
  • 如下我想打印小于UID100的用户
[root@localhost ~]# awk -F: '$3<=1000{print $1,$3}'  /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
games 12
ftp 14
nobody 99
systemd-bus-proxy 999
systemd-network 192
  • 如果我想打印UID大于100的用户
[root@localhost ~]# awk -F: '$3>=1000{print $1,$3}'  /etc/passwd
nfsnobody 65534
mageedu 1000
Linux基础之三剑客AWK基础篇_第1张图片
  • 逻辑操作符:与&&,或||,非!
  • 示例
[root@localhost ~]# awk -F: '$3>=0 && $3<=1000 {print $1,$3}' /etc/passwd   
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
games 12
ftp 14
nobody 99
systemd-bus-proxy 999
systemd-network 192
dbus 81
  • 或者小于10大于1000,的打印出来
[root@localhost ~]# awk -F: '$3<=0 || $3>=1000 {print $1,$3}' /etc/passwd  
root 0
nfsnobody 65534
mageedu 1000
  • 还可以取非
[root@localhost ~]# awk -F: '  !  ($3>1000) {print $1,$3}' /etc/passwd 
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
games 12
ftp 14
nobody 99
systemd-bus-proxy 999
systemd-network 192
dbus 81

正则表达式

  • 正则表达式要多练这里只举几个例子

  • 如果我只想用AWK来提取磁盘信息,怎么取,我们可以用包含来提取

[root@localhost ~]# df|awk '$0 ~ "^/dev/sd"' 
/dev/sda2       41922560  388520  41534040   1% /
/dev/sda3       20961280 2679012  18282268  13% /usr
/dev/sda1         508580  148756    359824  30% /boot
  • 当前里面还可以取反
[root@localhost ~]# df|awk '$0 !~ "^/dev/sd"' 
Filesystem     1K-blocks    Used Available Use% Mounted on
devtmpfs         2008832       0   2008832   0% /dev
tmpfs            2023456       0   2023456   0% /dev/shm
tmpfs            2023456    8800   2014656   1% /run
tmpfs            2023456       0   2023456   0% /sys/fs/cgroup
tmpfs             404692       0    404692   0% /run/user/0
Linux基础之三剑客AWK基础篇_第2张图片

BEGIN 和END 模块

  • 通常,对于每个输入行,awk 都会执行每个脚本代码块一次。然而,在许多编程情况中
  • 可能需要在awk 开始处理输入文件中的文本之前执行初始化代码。对于这种情况,awk 允许
  • 您定义一个BEGIN 块。我们在前一个示例中使用了BEGIN 块。因为awk 在开始处理输入文件之前会执行BEGIN 块
  • 因此它是初始化 FS(字段分隔符)变量、打印页眉或初始化其它
    在程序中以后会引用的全局变量的极佳位置

三目表达式

  • 三目就是三个元素,三个组成部分,第一部分冒号,以此类推
  • 示例
[root@localhost ~]# awk -F: '{$3>=1000?username="common user":username="sysuser";printf "%s  %s  %d\n" ,username,$1,$3}' /etc/passwd
sysuser  root  0
sysuser  bin  1
sysuser  daemon  2
sysuser  adm  3
sysuser  lp  4
sysuser  sync  5
sysuser  shutdown  6
sysuser  halt  7
sysuser  mail  8
sysuser  operator  11
sysuser  games  12
sysuser  ftp  14
sysuser  nobody  99
  • 或者来对齐下
[root@localhost ~]# awk -F: '{$3>=1000?username="common user":username="sysuser";printf "%s  %20s  %20d\n" ,username,$1,$3}' /etc/passwd 
sysuser                  root                     0
sysuser                   bin                     1
sysuser                daemon                     2
sysuser                   adm                     3
sysuser                    lp                     4
sysuser                  sync                     5
sysuser              shutdown                     6
sysuser                  halt                     7
sysuser                  mail                     8
sysuser              operator                    11
sysuser                 games                    12
sysuser                   ftp                    14
sysuser                nobody                    99
sysuser     systemd-bus-proxy                   999
sysuser       systemd-network                   192
sysuser                  dbus                    81
sysuser               polkitd                   998
sysuser                colord                   997
sysuser                  abrt                   173
sysuser        libstoragemgmt                   996
sysuser                   rpc                    32

你可能感兴趣的:(Linux基础之三剑客AWK基础篇)