Awk

Awk简介

  • Awk是一种编程语言,可以在Linux下对文本和数据进行扫描与处理,数据可以来自标准输入、文件、管道。

Awk工作流程

  • 逐行扫描文件 --> 从第一行到最后一行 --> 寻找匹配特定模式的行 --> 进行用户操作
  • Awk的两个特殊模式:

    1. BEGIN模式:awk将在读取任何输入行之前执行BEGIN中的操作。
    2. END模式:awk将在正式退出之前执行END中的操作。

Awk基本语法格式

gawk [选项] -f program-file [--] file ...
POSIX options:          GNU long options: (standard)
        -f progfile             --file=progfile
        -F fs                   --field-separator=fs
        -v var=val              --assign=var=val
Short options:          GNU long options: (extensions)
        -b                      --characters-as-bytes
        -c                      --traditional
        -C                      --copyright
        -d[file]                --dump-variables[=file]
        -e 'program-text'       --source='program-text'
        -E file                 --exec=file
        -g                      --gen-pot
        -h                      --help
        -L [fatal]              --lint[=fatal]
        -n                      --non-decimal-data
        -N                      --use-lc-numeric
        -O                      --optimize
        -p[file]                --profile[=file]
        -P                      --posix
        -r                      --re-interval
        -S                      --sandbox
        -t                      --lint-old
        -V                      --version

Awk操作指令

记录与字段

  • Awk一次从文件中读取一条记录,并将记录存储在字段变量$0中。记录为分割为字段并存储在$1,$2,...,$NF中(默认使用空格或制表符为分隔符)。
#读取输入行,并输出第一个字段、第二个字段、第三个字段
[root@Hyui-VM ~]# echo hello the world | awk '{print $1,$2,$3}'
hello the world
#读取输入行,直接输出该行
[root@Hyui-VM ~]# echo hello the world | awk '{print $0}'
hello the world
#输出该行的字段个数
[root@Hyui-VM ~]# echo hello the world | awk '{print NF}'
3
#输出该行最后一个字段
[root@Hyui-VM ~]# echo hello the world | awk '{print $NF}'
world

字段分隔符

  • Awk默认使用空格和制表符作为分隔符,使用-F和FS可以改变分隔符。
[root@Hyui-VM ~]# awk -F: '{print $1}' /etc/passwd
[root@Hyui-VM ~]# awk 'BEGIN {FS=":"} {print $1}' /etc/passwd
  • 以上两种方法都是将":"设定为分隔符,以":"为分隔符打印passwd文件的第一个字段。
  • 如何指定多个字段分隔符?
[root@Hyui-VM ~]# echo 'hello the:world,!' | awk 'BEGIN {FS="[:,]"} {print $1,$2,$3,$4}'
hello the world !

内置变量

变量列表

变量名称描 述
ARGC命令行参数个数
FILENAME当前输入文档名称
FNR当前输入文档当前记录编号
NR输入流的当前记录编号
NF当前记录的字段个数
FS字段分隔符
OFS输出字段分隔符,默认为空格
ORS输出记录分隔符,默认换行符n
RS输入记录分隔符,默认为n

示例1

[root@Hyui-VM ~]# cat neko.html 
<html>
<title>Neko Site</title>
<body>
h1Cute Nekoh1
h2Kawaii Nekoh2
h3Yasashi Nekoh3
</body>
</html>
[root@Hyui-VM ~]# cat network 
DEVICE=eno16777736
onboot=yes
BOOTPROTO=static
ipaddr=192.168.0.1
nEtMaSt=255.255.255.0
GaTeWaY=192.168.0.254
  • 输出当前文档的当前编号,第一个文件有8行,第二个文件有6行。
[root@Hyui-VM ~]# awk '{print FNR}' neko.html network 
1
2
3
4
5
6
7
8
1
2
3
4
5
6
  • 将两个文档作为一个整体输入流,通过NR输入当前编号。
[root@Hyui-VM ~]# awk '{print NR}' neko.html network 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  • 文档每行的字段数量。
[root@Hyui-VM ~]# awk '{print NF}' neko.html 
1
2
1
2
2
2
1
1

示例2

  • 通过OFS将输出分隔符设置为"-"。
[root@Hyui-VM ~]# cat test.txt 
This is a test file.
Welcome to CentOS Linux 7.
root@Hyui-VM ~]# awk 'BEGIN {OFS="-"} {print $1,$2,$3}' test.txt 
This-is-a
Welcome-to-CentOS

表达式与操作符

  • 操作符示例
[root@Hyui-VM ~]# echo "test" | awk 'x=2 {print x+3}'
5
[root@Hyui-VM ~]# echo "test" | awk 'x=2,y=3 {print x+3, y*3}'
5 9
#输出sshd_config所有空白行
[root@Hyui-VM ~]# awk '/^$/ {print x+=1}' /etc/ssh/sshd_config
1
2
3
4
5
......[省略]
#输出sshd_config总空白行个数
[root@Hyui-VM ~]# awk '/^$/ {x+=1} END {print x}' /etc/ssh/sshd_config 
27
#列出passwd的id大于500的用户名
[root@Hyui-VM ~]# awk -F: '$3>500 {print $1}' /etc/passwd
polkitd
chrony

Awk高级应用

If条件判断

  • 格式:
if (表达式)
动作1
else
动作2

if (表达式) 动作1; else 动作2
  • 判断vda1可用存储是否不足2G
[root@Hyui-VM ~]# df | grep vda1 | awk '{if($4<2000000) Print "Insufficient storage"; else print "OK"}'
OK

While循环

  • 格式1:
while(条件)
动作
  • 示例:
[root@Hyui-VM ~]# awk 'i=1 {} BEGIN {while(i<=5){++i; print i}}' neko.html 
1
2
3
4
5
6
  • 格式2:
do
动作
while(条件)
  • 示例:
[root@Hyui-VM ~]# awk 'BEGIN { do {++x; print x} while (x<=5)}' neko.html 
1
2
3
4
5
6

For循环

for (变量;条件;计数器)
  动作
  • 示例:
[root@Hyui-VM ~]# awk 'BEGIN {for (i=1;i<=5;i++) print i}' neko.html 
1
2
3
4
5

函数

rand()函数

  • 作用:产生0~1之间的浮点类型随机数。
  • 示例:
[root@Hyui-VM ~]# awk 'BEGIN{print rand(); srand(); print srand()}' test.txt 
0.237788
1585732218
  • 使用srand()使每次产生的随机数不同

gsub(x,y,z)函数

  • 作用:在字串z中使用字串y替换与正则表达式x相匹配的所有字串,z默认为$0。

sub(x,y,z)函数

  • 作用:在字串z中使用字串y替换与正则表达式x相匹配的di'yi'g字串,z默认为$0。
[root@Hyui-VM ~]# awk -F: 'gsub(/root/,"centos",$0) {print $0}' /etc/passwd 
centos:x:0:0:centos:/centos:/bin/bash
operator:x:11:0:operator:/centos:/sbin/nologin
[root@Hyui-VM ~]# awk -F: 'sub(/root/,"centos",$0) {print $0}' /etc/passwd 
centos:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/centos:/sbin/nologin

length(z)函数

  • 作用:计算并返回字串长度。
[root@Hyui-VM ~]# awk '{print length()}' test.txt 
20
26

getline函数

  • 作用:从输入中读取下一行内容。
[root@Hyui-VM ~]# df -h
Filesystem      Size  Used Avail Use% Mounted on
devtmpfs        1.9G     0  1.9G   0% /dev
tmpfs           1.9G     0  1.9G   0% /dev/shm
tmpfs           1.9G  424K  1.9G   1% /run
tmpfs           1.9G     0  1.9G   0% /sys/fs/cgroup
/dev/vda1        40G  2.1G   36G   6% /
tmpfs           379M     0  379M   0% /run/user/0
[root@Hyui-VM ~]# df -h | awk '{if(NF==1) {getline; print $3}; if(NF==6) print $4}'
1.9G
1.9G
1.9G
1.9G
36G
379M