typora/note/Shell/awk.md
2024-12-12 10:48:55 +08:00

195 lines
6.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

### 概念
- 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)