2020-07-17-Linux 命令之AWK

2020/07/17 LINUX

### AWK 是一种处理文本文件的语言,是一个强大的文本分析工具。

awk [选项参数] 'script' var=value file(s)awk [选项参数] -f scriptfile var=value file(s)

POSIX options:          GNU long options: (standard)
        -f progfile             --file=progfile 从脚本文件中读取awk命令。
        -F fs                   --field-separator=fs 指定输入文件折分隔符,fs是一个字符串或者是一个正则表达式,如-F:。
        -v var=val              --assign=var=val 赋值一个用户定义变量。
Short options:          GNU long options: (extensions)
        -b                      --characters-as-bytes
        -c                      --traditional
        -C                      --copyright
        -d[file]                --dump-variables[=file]
        -D[file]                --debug[=file]
        -e 'program-text'       --source='program-text'
        -E file                 --exec=file
        -g                      --gen-pot
        -h                      --help
        -i includefile          --include=includefile
        -l library              --load=library
        -L[fatal|invalid]       --lint[=fatal|invalid]
        -M                      --bignum
        -N                      --use-lc-numeric
        -n                      --non-decimal-data
        -o[file]                --pretty-print[=file]
        -O                      --optimize
        -p[file]                --profile[=file]
        -P                      --posix
        -r                      --re-interval
        -s                      --no-optimize
        -S                      --sandbox
        -t                      --lint-old
        -V                      --version   打印bug报告信息的版本。

内置变量

$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)

运算符

= += -= *= /= %= ^= **=	        赋值
?:	                            C条件表达式
||	                            逻辑或
&&	                            逻辑与
~                               和 !~	匹配正则表达式和不匹配正则表达式
< <= > >= != ==	                关系运算符
空格	                        连接
+ -	                            加,减
* / %	                        乘,除与求余
+ - !	                        一元加,减和逻辑非
^ ***	                        求幂
++ --	                        增加或减少,作为前缀或后缀
$	                            字段引用
in	                            数组成员

调用方法

1.命令行方式
awk [-F  field-separator]  'commands'  input-file(s)
其中,commands 是真正awk命令,[-F域分隔符]是可选的。 input-file(s) 是待处理的文件。
在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域。通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。

2.shell脚本方式
将所有的awk命令插入一个文件,并使awk程序可执行,然后awk命令解释器作为脚本的首行,一遍通过键入脚本名称来调用。
相当于shell脚本首行的:#!/bin/sh
可以换成:#!/bin/awk

3.将所有的awk命令插入一个单独文件,然后调用:
awk -f awk-script-file input-file(s)
其中,-f选项加载awk-script-file中的awk脚本,input-file(s)跟上面的是一样的。

实例

准备的内容

$ ps aux
      PID    PPID    PGID     WINPID   TTY         UID    STIME COMMAND
     1481    1480    1481       1956  pty0      197611 11:33:08 /usr/bin/bash
     1967    1481    1967       9968  pty0      197611 17:19:56 /usr/bin/ps
     1480       1    1480       1548  ?         197611 11:33:07 /usr/bin/mintty
基础实例
显示PPID列 $n 内建变量 FS默认是空格
$ ps aux | awk '{print $2}'
PPID
1481
1480
1

指定 分隔符 FS 为 ':' 也可以是正则表达式 也可以前面跟 -F 指定
$ ps aux | awk '{FS=":"} { print $0}'
      PID    PPID    PGID     WINPID   TTY         UID    STIME COMMAND
     1481    1480    1481       1956  pty0      197611 11:33:08 /usr/bin/bash
     2051    1481    2050      22224  pty0      197611 17:26:47 /usr/bin/bash
     2050    1481    2050      11672  pty0      197611 17:26:47 /usr/bin/ps
     1480       1    1480       1548  ?         197611 11:33:07 /usr/bin/mintty
$ ps aux | awk '{FS=":"} { print $1}'
PID
     1481    1480    1481       1956  pty0      197611 11
     1480       1    1480       1548  ?         197611 11
     2055    1481    2055       7996  pty0      197611 17
$ ps aux | awk '{FS=":"} { print $2}'
PPID
33
26
33
$ ps aux | awk '{FS=":"} { print $3}'
PGID
54 /usr/bin/ps
08 /usr/bin/bash
07 /usr/bin/mintty


$ ps aux | awk -F':' '{if(NR >2 ) print "结果是:"$3}'
结果是:47 /usr/bin/ps
结果是:07 /usr/bin/mintty


添加提示
$ ps aux | awk '{FS=":"} { print "结果是:"$3}'
结果是:PGID
结果是:08 /usr/bin/bash
结果是:40 /usr/bin/bash
结果是:40 /usr/bin/ps
结果是:07 /usr/bin/mintty

限制行数 显示 从第二行开始 使用内建变量 NR 假如是多文件就用 FNR(分文件计算行数)
$ ps aux | awk '{FS=":"} {if(NR > 2 ) print "结果是:"$3}'
结果是:08 /usr/bin/bash
结果是:41 /usr/bin/ps
结果是:07 /usr/bin/mintty
进阶实例(1)

准备的内容

> a.txt

1,a-1
2,a-2
3,a-3
4,a-4

> b.txt

2,b-2
4,b-4
5,b-5

$ ps aux | awk -F',' '{ print "结果是:" NR,FNR,$0}'  a.txt b.txt
结果是:1 1 1,a-1
结果是:2 2 2,a-2
结果是:3 3 3,a-3
结果是:4 4 4,a-4
结果是:5 1 2,b-2
结果是:6 2 4,b-4
结果是:7 3 5,b-5

$ awk -F',' 'NR==FNR{a[$1]=$2;}NR!=FNR{print $0,a[$1]}' b.txt a.txt
1,a-1
2,a-2 b-2
3,a-3
4,a-4 b-4

解释:
    a[] 是一个数组,在先读取 b.txt 文件的时候开始做一个暂存,当 NR==FNR时,并不会执行后面的 {print $0,a[$1]} 
    当 NR!=FNR 不会执行前面的 {a[$1]=$2;}
    此时 a[] 数组存的是 b.txt 文件中 以 逗号 前面的值为索引 逗号后面的为 值
    用 a文件中 逗号前面的值取数组中的值 并打印 a文件的行号。

总结

在这个实例中,我们共运用了 类似 if...else...的语句,也使用了 变量数组。
这个类似于 通过逗号前面的值 实现 a.txt left outer join b.txt 
进阶实例(2)

准备内容

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0  19360  1308 ?        Ss    2019   0:41 /sbin/init
root         2  0.0  0.0      0     0 ?        S     2019   0:00 [kthreadd]
root         3  0.0  0.0      0     0 ?        S     2019   0:25 [migration/0]
root         4  0.0  0.0      0     0 ?        S     2019   0:43 [ksoftirqd/0]
root         5  0.0  0.0      0     0 ?        S     2019   0:00 [stopper/0]
root         6  0.0  0.0      0     0 ?        S     2019   0:14 [watchdog/0]
root         7  0.0  0.0      0     0 ?        S     2019   0:25 [migration/1]
root         8  0.0  0.0      0     0 ?        S     2019   0:00 [stopper/1]
root         9  0.0  0.0      0     0 ?        S     2019   0:53 [ksoftirqd/1]
root        10  0.0  0.0      0     0 ?        S     2019   0:11 [watchdog/1]
root        11  0.0  0.0      0     0 ?        S     2019   0:23 [migration/2]
root        12  0.0  0.0      0     0 ?        S     2019   0:00 [stopper/2]

pattern 使用示例 分隔符是 ‘00’

$ awk -F00 '/stopper/  {print $0}' x.txt
root         5  0.0  0.0      0     0 ?        S     2019   0:00 [stopper/0]
root         8  0.0  0.0      0     0 ?        S     2019   0:00 [stopper/1]
root        12  0.0  0.0      0     0 ?        S     2019   0:00 [stopper/2]

$ awk -F00 '/stopper/  {print $1}' x.txt
root         5  0.0  0.0      0     0 ?        S     2019   0:
root         8  0.0  0.0      0     0 ?        S     2019   0:
root        12  0.0  0.0      0     0 ?        S     2019   0:

$ awk -F00 '/stopper/  {print $2}' x.txt
 [stopper/0]
 [stopper/1]
 [stopper/2]

print 与 printf

awk中同时提供了print和printf两种打印输出的函数。
其中print函数的参数可以是变量、数值或者字符串。字符串必须用双引号引用,参数用逗号分隔。如果没有逗号,参数就串联在一起而无法区分。这里,逗号的作用与输出文件的分隔符的作用是一样的,只是后者是空格而已。
printf函数,其用法和c语言中printf基本相似,可以格式化字符串,输出复杂时,printf更加好用,代码更易懂。
$ awk -F '00' '/stopper/  {printf "linenum: %s,content: %s \n" ,NR,$0}' x.txt
linenum: 6,content: root         5  0.0  0.0      0     0 ?        S     2019   0:00 [stopper/0]
linenum: 9,content: root         8  0.0  0.0      0     0 ?        S     2019   0:00 [stopper/1]
linenum: 13,content: root        12  0.0  0.0      0     0 ?        S     2019   0:00 [stopper/2]
进阶实例(3)

行数计数 准备内容同上

$ awk 'BEGIN{count = 0;print count} {count++;} END{print count}' x.txt
0
13
条件语句

计算 PID > 5 的之和 准备内容同上

$ awk 'BEGIN {count = 0} {if($2>5){count=count+$2;}} END {print "pid sum is = "count}' x.txt
pid sum is = 63
match 函数
awk 'BEGIN{start=match("this is a test",/[a-z]+$/); print start, RSTART, RLENGTH }'  x.txt

附录 常用字符串函数

下载选择 下载选择 …….

Search

    Table of Contents