Loading... 今天来简单说下 linux 三剑客之一 `awk`, 概念这里不再赘述,直接看示例: 如果熟悉,只是来看下总结,可点击[这里](#总结). 语法格式: ```bash awk [options] 'script' var=value file(s) ``` ## 测试文件 先创建两个测试文件: `class1.txt`: ```bash zhaoyun 85 87 guanyu 87 88 liubei 90 86 ``` `class2.txt`: ```bash caocao 92 87 90 guojia 99 96 92 ``` ## 1. 打印内容的第一列 打印文件的第一列,使用 `awk` 的 `print` 函数,`$1` 表示第一列 ```bash $ awk '{print $1}' class1.txt zhaoyun 85 ``` ## 2. 打印多列 比如我们想打印文件的第一列和第三列,可以这样写: ```bash $ awk '{print $1, $3}' class1.txt zhaoyun 87 guanyu 88 liubei 86 ``` ## 3. 打印首列和末列 - 首列可以使用 `$1` 表示 - 末列可以使用 `$NF` 表示,NF 表示目前的记录被分割的字段的数目,NF 可以理解为 _Number of Field_。 ```bash $ awk '{print $1,$NF}' class1.txt zhaoyun 87 guanyu 88 liubei 86 ``` ## 4. 打印倒数第 N 列 如果我们想打印倒数第二列,可以这样写: ```bash $ awk '{print $(NF-1)}' class1.txt 85 87 90 ``` ## 5. 打印行号 打印行号,使用 `NR` 变量,如: ```bash $ awk '{print NR, $0}' class1.txt 1 zhaoyun 85 87 2 guanyu 87 88 3 liubei 90 86 ``` - `NR` _Number of Records_ 表示行号,注意前面没有 `$` 符号, 如果加了 `$NR` 表示第 `NR` 列。 - `$0` 表示整行内容。 如果我们想要在行号后加个点呢,可以这样写: ```bash $ awk '{print NR".", $0}' class1.txt 1. zhaoyun 85 87 2. guanyu 87 88 3. liubei 90 86 ``` ## 6. 指定分隔符 awk 默认是以空格分隔,如果是其他分隔符,可以使用 `-F` 参数指定,如以逗号分隔(先手动修改下之前的 class1.txt 为逗号分割): ```bash awk -F, '{print $1}' class1.txt awk -F , '{print $1}' class1.txt awk -F ',' '{print $1}' class1.txt ``` 上面三种写法都行, 还能用指定内置变量 `FS` 来指定分隔符,如: ```bash awk -v FS=, '{print $1}' class1.txt ``` ## 7. 分别指定输入和输出分隔符 前面我们指定的分隔符是输入分隔符,输出默认还是空格,如果我们想指定输出分隔符,可以指定内置变量 `OFS`,如: ```bash awk -v FS=, -v OFS=- '{print $1, $2}' class1.txt ``` 这样输入分隔符是 `,` 输出分隔符是 `-` ## 8. 多文件行号独立 对于多个文件,如果直接使用之前的 `NR` 变量,每个文件的行号是连续的,如: ```bash $ awk '{print NR, $0}' class1.txt class2.txt 1 zhaoyun 85 87 2 guanyu 87 88 3 liubei 90 86 4 caocao 92 87 90 5 guojia 99 96 92 ``` 想要独立行号,可以使用 `FNR` 变量,如: ```bash $ awk '{print FNR, $0}' class1.txt class2.txt 1 zhaoyun 85 87 2 guanyu 87 88 3 liubei 90 86 1 caocao 92 87 90 2 guojia 99 96 92 ``` ## 9. 输出文件名 如果在上面那个的基础上,想要输出文件名,可以使用内置变量 `FILENAME`,如: ```bash $ awk '{print FILENAME, FNR, $0}' class1.txt class2.txt class1.txt 1 zhaoyun 85 87 class1.txt 2 guanyu 87 88 class1.txt 3 liubei 90 86 class2.txt 1 caocao 92 87 90 class2.txt 2 guojia 99 96 92 ``` ## 10. 前置后置操作 还是刚才那个例子,如果我们想在内容前后输出点内容,那么可以使用 `BEGIN` 和 `END` 操作符,如: ```bash $ awk 'BEGIN{print "start"} {print FNR, $1, $2, $3} END{print "end"}' class1.txt class2.txt start 1 zhaoyun 85 87 2 guanyu 87 88 3 liubei 90 86 1 caocao 92 87 2 guojia 99 96 end ``` 比如用 `NR` 组合 `End` 就可以统计一个文件的行数: ```bash $ awk 'END {print NR}' class1.txt 3 ``` ## 11. 文件级的前置后置操作 如果想要在每个文件开始读取和读取结束时执行一些操作,可以使用 `BEGINFILE` 和 `ENDFILE` 操作符,如用来统计每个文件的行数: ```bash $ awk 'BEGINFILE{print "文件:", FILENAME} ENDFILE{print "行数:", FNR}' class1.txt class2.txt 文件: class1.txt 行数: 3 文件: class2.txt 行数: 2 ``` > `BEGINFILE` 和 `ENDFILE` 操作符是 gawk 特有的,其他版本可能不支持。 ## 12. 接收外部变量 如果我们想要在 `awk` 脚本中接收外部变量,比如变量声明输出分隔符,可以使用 `-v` 参数,如: ```bash $ var1="_" $ awk -v OFS=$var1 '{print $1, $2, $3}' class1.txt zhaoyun_85_87 guanyu_87_88 liubei_90_86 ``` ## 13. 判断条件 如果我们想要在 `awk` 中加入判断条件,可以使用 `if` 语句,如只输出第 2-3 行: ```bash awk '{if (NR == 2 || NR == 3) print $0}' class1.txt ``` ## 总结 ### 参数 - `-F`: 指定分隔符, 默认是空格, 也可以使用内置变量 `FS` 来指定分隔符, 如 `-v FS=,` ### 变量 - `$0`: 表示整行内容 - `$1`: 第一列 - `NR`:Number of Records, 表示行号 - `$NR`: 前面加上了 `$` 符号,表示第 `NR` 行 - `NF`: Number of Fields, 表示目前的记录被分割的字段的数目 - `$NF`: 前面加上了 `$` 符号,表示最后一列 - `FNR`: File Number of Records, 表示当前文件的行号, 多文件时行号独立 - `FILENAME`: 当前输入文件的名称 - `FS`: Field Separator, 输入分隔符 - `OFS`: Output Field Separator, 输出分隔符 最后修改:2024 年 04 月 30 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 如果觉得我的文章对你有用,请我喝杯咖啡吧。