awk学习笔记

107 阅读4分钟

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) }   
``` |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

**