### 概念
- awk 是一种编程语言，对文件和数据进行处理
- 数据可以来自标准输入，一个或多个文件，或其他命令的输出
- 朱行扫描文件爱你，默认从第一行到最后一行，寻找匹配的特定模式的行

### 语法结构
- awk 选项 '命令部分' 文件名
- 引用shell变量需要使用双引号引起

### 常用选项介绍
- -F 定义字段分割符号，默认的分隔符是空格
- -v 定义变量并赋值

### 命名部分说明
![59e2e6e78b7e5d8f0b2bf74c16f74ff0.png](../../_resources/59e2e6e78b7e5d8f0b2bf74c16f74ff0.png)

### 内置变量
- $n	当前记录的第n个字段，字段间由FS分隔
- $0	完整的输入记录
- ARGC	命令行参数的数目
- ARGIND	命令行中当前文件的位置(从0开始算)
- ARGV	包含命令行参数的数组
- CONVFMT	数字转换格式(默认值为%.6g)ENVIRON环境变量关联数组
- ERRNO	最后一个系统错误的描述
- FIELDWIDTHS	字段宽度列表(用空格键分隔)
- FILENAME	当前文件名
- FNR	各文件分别计数的行号
- FS	字段分隔符(默认是任何空格)
- IGNORECASE	如果为真，则进行忽略大小写的匹配
- NF	一条记录的字段的数目
- NR	已经读出的记录数，就是行号，从1开始
- OFMT	数字的输出格式(默认值是%.6g)
- OFS	输出字段分隔符，默认值与输入字段分隔符一致。
- ORS	输出记录分隔符(默认值是一个换行符)
- RLENGTH	由match函数所匹配的字符串的长度
- RS	记录分隔符(默认是一个换行符)
- RSTART	由match函数所匹配的字符串的第一个位置
- SUBSEP	数组下标分隔符(默认值是/034)

### 实践
- 打印文件的每一行
```
[sunqi@manjaro-vm shell_demo]$ awk 'NR=1,NR=5{print $0}' passwd
root:x:0:0::/root:/bin/bash
nobody:x:65534:65534:Kernel Overflow User:/:/usr/bin/nologin
dbus:x:81:81:System Message Bus:/:/usr/bin/nologin
bin:x:1:1::/:/usr/bin/nologin
daemon:x:2:2::/:/usr/bin/nologin
mail:x:8:12::/var/spool/mail:/usr/bin/nologin
ftp:x:14:11::/srv/ftp:/usr/bin/nologin
http:x:33:33::/srv/http:/usr/bin/nologin
systemd-coredump:x:981:981:systemd Core Dumper:/:/usr/bin/nologin
systemd-network:x:980:980:systemd Network Management:/:/usr/bin/nologin
```

- 打印第一行到第五行
```
[sunqi@manjaro-vm shell_demo]$ awk 'NR==1,NR==5{print $0}' passwd  
root:x:0:0::/root:/bin/bash
nobody:x:65534:65534:Kernel Overflow User:/:/usr/bin/nologin
dbus:x:81:81:System Message Bus:/:/usr/bin/nologin
bin:x:1:1::/:/usr/bin/nologin
daemon:x:2:2::/:/usr/bin/nologin
[sunqi@manjaro-vm shell_demo]$

me@me-EQ59:~/shell_demo$ awk 'NR>=3 && NR<=5 {print $0}' passwd
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
me@me-EQ59:~/shell_demo$
```


- 打印第一行或第五行
```
me@me-EQ59:~/shell_demo$ awk 'NR==1 || NR==5 {print $0}' passwd
root:x:0:0:root:/root:/bin/bash
sync:x:4:65534:sync:/bin:/bin/sync
me@me-EQ59:~/shell_demo$
```

- 打印 冒号 分割第一行，最后一行和倒数第二行
```
me@me-EQ59:~/shell_demo$ awk -F: '{print $1, $NF, $(NF-1)}' passwd
root /bin/bash /root
daemon /usr/sbin/nologin /usr/sbin
bin /usr/sbin/nologin /bin
sys /usr/sbin/nologin /dev
sync /bin/sync /bin
games /usr/sbin/nologin /usr/games
man /usr/sbin/nologin /var/cache/man
lp /usr/sbin/nologin /var/spool/lpd
mail /usr/sbin/nologin /var/mail
news /usr/sbin/nologin /var/spool/news
```

- 以 冒号 分割，包含root关键字的行的第一列和最后一列
```
me@me-EQ59:~/shell_demo$ awk -F: '/root/{print $1,$NF}' passwd
root /bin/bash
nm-openvpn /usr/sbin/nologin
me@me-EQ59:~/shell_demo$
```

- 自定义结果输出分隔符
```
me@me-EQ59:~/shell_demo$ awk -F: 'BEGIN{OFS="#"}/root/{print $1,$NF}' passwd
root#/bin/bash
nm-openvpn#/usr/sbin/nologin
me@me-EQ59:~/shell_demo$ awk -F: '/root/{print $1"###"$NF}' passwd
root###/bin/bash
nm-openvpn###/usr/sbin/nologin
me@me-EQ59:~/shell_demo$
```

### 格式化输出
- print 类似echo
- printf 类似 echo -n
- %s 字符类型
- %d 数值类型
- %-15s 占15字符，- 表示左对齐，默认是右对齐
- printf 默认不会在行尾自动换行，加`\n`
```
me@me-EQ59:~/shell_demo$ awk -F: '{printf "%-15s %-10s %-15s\n", $1,$2,$3}' passwd
root            x          0
daemon          x          1
bin             x          2
sys             x          3
sync            x          4
games           x          5
man             x          6
lp              x          7
mail            x          8
news            x          9
```

### 变量定义
- -v 变量名=变量值
- 调用变量不需要使用 $ 符号
```
me@me-EQ59:~/shell_demo$ head -n 5 /etc/passwd > passwd
me@me-EQ59:~/shell_demo$ cat passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
me@me-EQ59:~/shell_demo$ awk -v NUM=4 -F: '{ print $NUM }' passwd
0
1
2
3
65534
me@me-EQ59:~/shell_demo$ awk -v NUM=4 -F: '{ print NUM }' passwd
4
4
4
4
4
me@me-EQ59:~/shell_demo$
```

### begin end
- begin 表示在程序开始前执行
- end 表示在所有文件处理完后执行
- 'BEGIN{开始处理之前};{处理中};END{处理结束后}'
```
me@me-EQ59:~/shell_demo$ cat passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
me@me-EQ59:~/shell_demo$ awk -v NUM=4 -F: 'BEGIN{print "user\tshell_name"};{ print $1"\t"$NF };END{print "user\tshell_name"}' passwd
user	shell_name
root	/bin/bash
daemon	/usr/sbin/nologin
bin	/usr/sbin/nologin
sys	/usr/sbin/nologin
sync	/bin/sync
user	shell_name
me@me-EQ59:~/shell_demo$
```

### 实践
- 正则匹配从某一行到某一行
![99275e98a56fc125fcba3c17489f58a4.png](../../_resources/99275e98a56fc125fcba3c17489f58a4.png)

- 正则筛选行然后打印行
![0746d379ccf516f12052987cdb69d62e.png](../../_resources/0746d379ccf516f12052987cdb69d62e.png)

- 支持逻辑运算符 `&&`、 `||`和`!` 
![130836e5300e6e1e037d37ee040bb7b1.png](../../_resources/130836e5300e6e1e037d37ee040bb7b1.png)
![1929245ee849038cfe1a9d5da7fc3443.png](../../_resources/1929245ee849038cfe1a9d5da7fc3443.png)
![7f95339bd98c5f0bee5868e52d28ee80.png](../../_resources/7f95339bd98c5f0bee5868e52d28ee80.png)