awk 也是一个数据处理工具。和grep,sed,awk并称linux文件处理三剑客、三板斧。
grep 更适合单纯的查找或匹配文本
sed 更适合编辑匹配到的文本,适合处理“一整行”
awk 更适合格式化文本,对文本进行较复杂格式处理,适合“列”数据。适合“按行”处理,一些小型文本数据,比如log文件。
语法格式:
| ``` awk '条件类型1{操作1} 条件类型2{操作2} ...’ filename1 filename2 ... 或 awk [选项参数] 'script' var=value file(s)
| -------------------------------------------------------------------------------------------------------- |
加上脚本:
| ```
BEGIN {<initializations>} <pattern 1> {<program actions>} <pattern 2> {<program actions>} ... END {< final actions >}
``` |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
须知: awk 主要是处理“每一行的字段内的数据”,而默认的“字段的分隔符号为 “空白键” 或 “[tab]键”。
**常用方法:通过print的功能将字段数据列出来:**
> 比如文件长这样:
>
> | ```
> [[email protected] ~]$ last -n 5 <==仅取出前五行 dmtsai pts/0 192.168.1.100 Tue Jul 14 17:32 still logged in dmtsai pts/0 192.168.1.100 Thu Jul 9 23:36 - 02:58 (03:22) dmtsai pts/0 192.168.1.100 Thu Jul 9 17:23 - 23:36 (06:12) dmtsai pts/0 192.168.1.100 Thu Jul 9 08:02 - 08:17 (00:14) dmtsai tty1 Fri May 29 11:55 - 12:11 (00:15)
> ``` |
> | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
>
> 若我想要取出帐号与登陆者的 IP ,且帐号与 IP 之间以 [tab] 隔开,则会变成这样:
>
> | ```
> [[email protected] ~]$ last -n 5 | awk '{print $1 "\t" $3}' dmtsai 192.168.1.100 dmtsai 192.168.1.100 dmtsai 192.168.1.100 dmtsai 192.168.1.100 dmtsai Fri
> ``` |
> | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
>
> 一个脚本的例子,查找passwd文件里没有login或者shutdown字段的行数
>
> | ```
> awk ' BEGIN { print "\n>>>Start" } !/(login|shutdown)/ { print NR, $0 } END { print "<<<END\n" } ' /etc/passwd
> ``` |
> | ----------------------------------------------------------------------------------------------------------------------------------- |
#### [](http://lizhiyuan.club/2021/11/25/awk-note/#awk%E7%9A%84%E5%A4%84%E7%90%86%E6%B5%81%E7%A8%8B%EF%BC%9A "awk的处理流程:")awk的**处理流程**:
1. 读入第一行,并将改行数据按字段填入 $1 $2 $3…. 等变量当中;
1. 依据 “条件类型” 的限制,判断是否需要进行后面的 “动作”;
1. 做完所有的动作与条件类型;
1. 重复上面 1~3 的步骤,处理剩下的行。
### [](http://lizhiyuan.club/2021/11/25/awk-note/#awk%E5%8F%82%E6%95%B0%E9%80%89%E9%A1%B9 "awk参数选项")awk参数选项
**常用:**
-F fs or –field-separator fs\
指定输入文件折分隔符,fs是一个字符串或者是一个正则表达式,如-F:。
-v var=value or –asign var=value\
赋值一个用户定义变量。
-f scripfile or –file scriptfile\
从脚本文件中读取awk命令。
**其他:**
- -mf nnn and -mr nnn\
对nnn值设置内在限制,-mf选项限制分配给nnn的最大块数目;-mr选项限制记录的最大数目。这两个功能是Bell实验室版awk的扩展功能,在标准awk中不适用。
- -W compact or –compat, -W traditional or –traditional\
在兼容模式下运行awk。所以gawk的行为和标准的awk完全一样,所有的awk扩展都被忽略。
- -W copyleft or –copyleft, -W copyright or –copyright\
打印简短的版权信息。
- -W help or –help, -W usage or –usage\
打印全部awk选项和每个选项的简短说明。
- -W lint or –lint\
打印不能向传统unix平台移植的结构的警告。
- -W lint-old or –lint-old\
打印关于不能向传统unix平台移植的结构的警告。
- -W posix\
打开兼容模式。但有以下限制,不识别:/x、函数关键字、func、换码序列以及当fs是一个空格时,将新行作为一个域分隔符;操作符**和**=不能代替^和^=;fflush无效。
- -W re-interval or –re-inerval\
允许间隔正则表达式的使用,参考(grep中的Posix字符类),如括号表达式[[:alpha:]]。
- -W source program-text or –source program-text\
使用program-text作为源代码,可与-f命令混用。
- -W version or –version\
打印bug报告信息的版本。
## [](http://lizhiyuan.club/2021/11/25/awk-note/#awk%E5%8F%98%E9%87%8F "awk变量")awk变量
#### [](http://lizhiyuan.club/2021/11/25/awk-note/#%E5%B8%B8%E7%94%A8%E5%86%85%E7%BD%AE%E5%8F%98%E9%87%8F%EF%BC%9A "常用内置变量:")常用内置变量:
| 变量名 | 描述 |
| --------------------------- | ------------------------------------------------ |
| FS(Field Separator) | 输入的分隔符,默认是空格和tab。 |
| OFS(Out of Field Separator) | 输出的分隔符,默认与输入字段分隔符一样。 |
| NR(Number of Record) | 行数,从1开始。在 END 部分用就是文件中的所有记录的总条数。 |
| NF(Number for Field) | 字段数,该行一共几个字段。配合NR可以非常容易的发现那些数据丢失了。 |
| RS(Record Separator) | 输入记录分隔符(输入换行符),默认是\n, 一般在每个记录本来就分行的时候用,可设置为\n\n。 |
| ORS(Output Record Separate) | 输出记录分隔符(输出换行符),输出时用指定符号代替换行符。 |
| FNR | 当前文件的记录数。如果输入多个文件,NR代表所有输入文件的全部记录数。 |
| FILENAME | 当前文件名 |
#### [](http://lizhiyuan.club/2021/11/25/awk-note/#%E8%87%AA%E5%AE%9A%E4%B9%89%E5%8F%98%E9%87%8F%E7%9A%84%E6%96%B9%E6%B3%95%EF%BC%9A "自定义变量的方法:")自定义变量的方法:
- 法一:-v 变量名= 值(变量名区分大小写) 例:`awk -va=1 -vb=2`
- 法二:在{pattern} 中定义,例:`awk '{total = $1+$2 print total}'`
- 法三:直接获取shell的变量,例:`awk 'BEGIN{print "'$var'"}'`注意是“双引号+单引号+shell变量+单引号+双引号”的格式。
#### [](http://lizhiyuan.club/2021/11/25/awk-note/#%E5%85%B6%E4%BB%96%E5%86%85%E7%BD%AE%E5%8F%98%E9%87%8F%EF%BC%9A "其他内置变量:")其他内置变量:
| 变量 | 描述 |
| :---------- | :------------------------------ |
| $n | 当前记录的第n个字段,字段间由FS分隔 |
| $0 | 完整的输入记录 |
| ARGC | 命令行参数的数目 |
| ARGIND | 命令行中当前文件的位置(从0开始算) |
| ARGV | 包含命令行参数的数组 |
| CONVFMT | 数字转换格式(默认值为%.6g)ENVIRON环境变量关联数组 |
| ERRNO | 最后一个系统错误的描述 |
| FIELDWIDTHS | 字段宽度列表(用空格键分隔) |
| FILENAME | 当前文件名 |
| IGNORECASE | 忽略大小写,如果为真,则进行忽略大小写的匹配 |
| OFMT | 数字的输出格式(默认值是%.6g) |
| RLENGTH | 由match函数所匹配的字符串的长度 |
| RSTART | 由match函数所匹配的字符串的第一个位置 |
| SUBSEP | 数组下标分隔符(默认值是/034) |
#### [](http://lizhiyuan.club/2021/11/25/awk-note/#%E6%B3%A8%E6%84%8F%E7%82%B9%EF%BC%9A "注意点:")注意点:
- awk记得用 **“”双引号** ,如果想要以 print 打印时格式内容时。非变量的文字部分,包含printf的格式中,都需要使用双引号来定义出来,因为单引号已经是 awk 的指令固定用法。
- Awk的**命令间隔**:
- awk 的指令间隔:即在 {} 内的动作,如果有需要多个指令辅助时,可利用分号“;”间隔, 或者直接以 [Enter] 按键来隔开每个指令,例如上面的范例中。如果是管道符|之后换行,用反斜杠\
- 逻辑运算当中,如果是“等于”的情况,则务必使用两个等号“==”。(一个“=”是用来赋值的。)
- 格式化输出时,在 printf 的格式设置当中,务必加上 \n ,才能进行分行。
- 与 bash shell 的变量不同,在 awk 当中,变量可以直接使用,不需加上 $ 符号。
## [](http://lizhiyuan.club/2021/11/25/awk-note/#awk%E5%85%B6%E4%BB%96%E8%AF%AD%E6%B3%95 "awk其他语法")awk其他语法
#### [](http://lizhiyuan.club/2021/11/25/awk-note/#%E5%BE%AA%E7%8E%AF "循环")循环
awk可以使用for,while,continue,break,exit
| ```
for (initialisation; condition; increment/decrement) action 或 while (condition) action 或 do action while (condition)
``` |
| ----------------------------------------------------------------------------------------------------------------------------------------- |
| ```
$ awk 'BEGIN { for (i = 1; i <= 5; ++i) print i }' $ awk 'BEGIN {i = 1; while (i < 6) { print i; ++i } }'
``` |
| ------------------------------------------------------------------------------------------------------------------ |
exit:Exit 用于结束脚本程序的执行。该函数接受一个整数作为参数表示 AWK 进程结束状态。 如果没有提供该参数,其默认状态为 0 。
| ```
$ awk 'BEGIN { sum = 0; for (i = 0; i < 20; ++i) { sum += i; if (sum > 50) exit(10); else print "Sum =", sum } }' $ echo $?
``` |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
输出:
| ```
Sum = 0 Sum = 1 Sum = 3 Sum = 6 Sum = 10 Sum = 15 Sum = 21 Sum = 28 Sum = 36 Sum = 45 10
``` |
| ------------------------------------------------------------------------------------------------- |
#### [](http://lizhiyuan.club/2021/11/25/awk-note/#%E5%88%A4%E6%96%AD "判断")判断
awk可以使用if,if-else ,或者if-else-if
——甚至是switch case进行选择
| ```
if (condition) action 或者 if (condition) { action-1 action-2 action-n }
``` |
| ------------------------------------------------------------------------------------ |
例:判断奇偶数
| ```
$ awk 'BEGIN {num = 10; if (num % 2 == 0) printf "%d is even number.\n", num }' #10 is even number. $ awk 'BEGIN {num = 11; if (num % 2 == 0) printf "%d is even number.\n", num; else printf "%d is odd number.\n", num }' #11 is odd number. $ awk 'BEGIN { a=30; if (a==10) print "a = 10"; else if (a == 20) print "a = 20"; else if (a == 30) print "a = 30"; }' #a = 30
``` |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
## [](http://lizhiyuan.club/2021/11/25/awk-note/#awk%E6%AD%A3%E5%88%99%E2%80%94%E2%80%94%E5%92%8C%E6%99%AE%E9%80%9A%E6%AD%A3%E5%88%99%E4%B8%80%E6%A0%B7%EF%BC%8C%E8%BF%99%E9%87%8C%E5%A4%8D%E4%B9%A0%E4%B8%80%E4%B8%8B "awk正则——和普通正则一样,这里复习一下")awk正则——和普通正则一样,这里复习一下
| ```
输出第二列包含 "th",并打印第二列与第四列 $ awk '$2 ~ /th/ {print $2,$4}' log.txt --------------------------------------------- this a
``` |
| ----------------------------------------------------------------------------------------------------------------------------- |
**~ 表示模式开始。// 中是模式。**
| ```
# 输出包含 "re" 的行 $ awk '/re/ ' log.txt --------------------------------------------- 3 Are you like awk 10 There are orange,apple,mongo
``` |
| ---------------------------------------------------------------------------------------------------------------------------------------------- |
***
## [](http://lizhiyuan.club/2021/11/25/awk-note/#%E5%BF%BD%E7%95%A5%E5%A4%A7%E5%B0%8F%E5%86%99 "忽略大小写")忽略大小写
| ```
$ awk 'BEGIN{IGNORECASE=1} /this/' log.txt --------------------------------------------- 2 this is a test This's a test
``` |
| -------------------------------------------------------------------------------------------------------------------------------- |
***
## [](http://lizhiyuan.club/2021/11/25/awk-note/#%E6%A8%A1%E5%BC%8F%E5%8F%96%E5%8F%8D "模式取反")模式取反
| ```
$ awk '$2 !~ /th/ {print $2,$4}' log.txt --------------------------------------------- Are like a There orange,apple,mongo $ awk '!/th/ {print $2,$4}' log.txt --------------------------------------------- Are like a There orange,apple,mongo
``` |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
#### [](http://lizhiyuan.club/2021/11/25/awk-note/#%E7%82%B9%EF%BC%88Dot%EF%BC%89 "点(Dot)")点(Dot)
点字符(.)可以匹配除了行结束字符的所有字符。比如下面的便子就可以匹配 fin, fun, fan 等等。
| ```
$ echo -e "cat\nbat\nfun\nfin\nfan" | awk '/f.n/'
``` |
| ---------------------------------------------------------- |
执行上面命令可以得到如下结果:
| ```
fun fin fan
``` |
| -------------------- |
#### [](http://lizhiyuan.club/2021/11/25/awk-note/#%E8%A1%8C%E5%BC%80%E5%A7%8B "行开始")行开始
行开始符(^)匹配一行的开始。下面的示例将输出所有以字符串 The 开始的行。
| ```
$ echo -e "This\nThat\nThere\nTheir\nthese" | awk '/^The/'
``` |
| ------------------------------------------------------------------- |
执行上面的命令可以得到如下结果:
| ```
There Their
``` |
| -------------------- |
#### [](http://lizhiyuan.club/2021/11/25/awk-note/#%E8%A1%8C%E7%BB%93%E6%9D%9F "行结束")行结束
行结束符($)匹配一行的结束。下面的例子中将输出所有以字符 n 结束的行:
| ```
$ echo -e "knife\nknow\nfun\nfin\nfan\nnine" | awk '/n$/'
``` |
| ------------------------------------------------------------------ |
执行上面的命令可以得到如下结果:
| ```
Ca fin fan
``` |
| ------------------- |
#### [](http://lizhiyuan.club/2021/11/25/awk-note/#%E5%8C%B9%E9%85%8D%E5%AD%97%E7%AC%A6%E9%9B%86 "匹配字符集")匹配字符集
匹配字符集用于匹配集合(由方括号表示)中的一个字符。如下例子中,匹配 Call 与 Tall 而不会匹配 Ball。
| ```
$ echo -e "Call\nTall\nBall" | awk '/[CT]all/'
``` |
| ------------------------------------------------------- |
执行上面的命令可以得到如下结果:
| ```
Call Tall
``` |
| ------------------ |
#### [](http://lizhiyuan.club/2021/11/25/awk-note/#%E6%8E%92%E9%99%A4%E9%9B%86 "排除集")排除集
正则匹配时会排除集合中的字符。如下例子中只会输出 Ball。
| ```
$ echo -e "Call\nTall\nBall" | awk '/[^CT]all/'
``` |
| -------------------------------------------------------- |
执行上面的命令可以得到如下结果:
| ```
Ball
``` |
| ------------- |
#### [](http://lizhiyuan.club/2021/11/25/awk-note/#%E6%88%96 "或")或
竖线(|)允许正则表达式实现逻辑或运算. 下面例子将会输出 Ball 与 Call 。
| ```
$ echo -e "Call\nTall\nBall\nSmall\nShall" | awk '/Call|Ball/'
``` |
| ----------------------------------------------------------------------- |
执行上面的命令可以得到如下结果:
| ```
Call Ball
``` |
| ------------------ |
#### [](http://lizhiyuan.club/2021/11/25/awk-note/#%E6%9C%80%E5%A4%9A%E5%87%BA%E7%8E%B0%E4%B8%80%E6%AC%A1 "最多出现一次")最多出现一次
该符号( ?)前面的字符不出现或者出现一次。如下示例匹配 Colour 与 Color。 使用 ? 使得 u 变成了可选字符 。
| ```
$ echo -e "Colour\nColor" | awk '/Colou?r/'
``` |
| ---------------------------------------------------- |
执行上面的命令可以得到如下结果:
| ```
Colour Color
``` |
| --------------------- |
#### [](http://lizhiyuan.club/2021/11/25/awk-note/#%E5%87%BA%E7%8E%B0%E9%9B%B6%E6%AC%A1%E6%88%96%E5%A4%9A%E6%AC%A1 "出现零次或多次")出现零次或多次
该符号(*) 允许其前的字符出现多次或者不出现。如下示例将匹配 ca,cat, catt 等等。
| ```
$ echo -e "ca\ncat\ncatt" | awk '/cat*/'
``` |
| ------------------------------------------------- |
执行上面的命令可以得到如下结果:
| ```
ca cat catt
``` |
| -------------------- |
#### [](http://lizhiyuan.club/2021/11/25/awk-note/#%E5%87%BA%E7%8E%B0%E4%B8%80%E6%AC%A1%E6%88%96%E5%A4%9A%E6%AC%A1 "出现一次或多次")出现一次或多次
该符号(+)使得其前的字符出现一次或者多次。下面的例子会匹配一个 2 或者多个连续的 2。
| ```
$ echo -e "111\n22\n123\n234\n456\n222" | awk '/2+/'
``` |
| -------------------------------------------------------------- |
执行上面的命令可以得到如下结果:
| ```
22 123 234 222
``` |
| ----------------------- |
#### [](http://lizhiyuan.club/2021/11/25/awk-note/#%E5%88%86%E7%BB%84 "分组")分组
括号用于分组而字符 | 用于提供多种选择。如下的正则表达式会匹配所有包含 Apple Juice 或 Aplle Cake 的行。
| ```
$ echo -e "Apple Juice\nApple Pie\nApple Tart\nApple Cake" | awk '/Apple (Juice|Cake)/'
``` |
| ------------------------------------------------------------------------------------------------ |
执行上面的命令可以得到如下结果:
| ```
Apple Juice Apple Cake
``` |
| ------------------------------- |
## [](http://lizhiyuan.club/2021/11/25/awk-note/#awk%E5%87%BD%E6%95%B0 "awk函数")awk函数
awk有很多[内置函数](https://www.runoob.com/w3cnote/awk-built-in-functions.html)
其他自定义函数的格式为:
| ```
function function_name(argument1, argument2, ...) { function body return 返回值 }
``` |
| ----------------------------------------------------------------------------------------------- |
例子+执行函数
| ```
function find_min(num1, num2) { if (num1 < num2) return num1 return num2 } function find_max(num1, num2) { if (num1 > num2) return num1 return num2 } function main(num1, num2) { result = find_min(10, 20) #这个函数还需要提前定义好 print "Minimum =", result result = find_max(10, 20) print "Maximum =", result } #运行函数: BEGIN { main(10, 20) }
``` |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
**