网络知识 娱乐 linux之awk超详解

linux之awk超详解

linux之awk详解

1、awk简介

awk是一种编程语言,用于linux下对文本和数据进行处理。数据可以来来自标准输入一个或多个文件,或其他命令的输出

更多作为脚本来使用。

awk处理数据的方式:逐行扫描文件,寻找匹配的特定模式的行,并在这些行上进行你想要的操作。如果没有指定动作,则把匹配的行显示到标准输出(屏幕)。如果没有指定模式,则所有被操作所指定的行都被处理。

2、选项

选项含义备注
-f从脚本文件中读取awk命令。常用
-F指定输入文件折分隔符,fs是一个字符串或者是一个正则表达式,如-F: (–field-separator)常用
-v赋值一个用户定义变量。

3、内置变量

变量解释备注
FS保存或设置字段分隔符,如FS=”:”
$n指定分隔的第n个字段,如$1、$3分别表示第1、第3列.$0代表输入整行内容
NFnumber of fields,当前行的字段数
NR记录当前已经读入行的数量
FNR当前行在源文件中的行数
OFSThe output field separator, a space by default.
ORSThe output record separator, by default a newline.
RSThe input record separator, by default a newline.
RTThe record terminator.

4、表达式

表达式含义
BEGINBEGIN和END是两种特殊的模式,没有针对输入进行测试。所有BEGIN模式的动作部分都被合并,就好像所有语句都写在一个BEGIN块中一样。它们在读取任何输入之前执行。
END所有的结束块都被合并,当所有的输入都被耗尽时(或者当执行exit语句时)执行。开始和结束模式不能与模式表达式中的其他模式组合。开始和结束模式不能缺少动作部分。
BEGINFILEBEGINFILE和ENDFILE是附加的特殊模式,其主体在读取每个命令行输入文件的第一条记录之前和读取每个文件的最后一条记录之后执行。
ENDFILE
/regular expression/对于/regular expression/patterns,将对与正则表达式匹配的每个输入记录执行关联语句。正则表达式与egrep(1)中的表达式相同,总结如下。
relational expression关系表达式可以使用下面关于操作一节中定义的任何运算符。它们通常测试某些字段是否与某些正则表达式匹配。
pattern && pattern逻辑AND,与C中的运算符相同。它们进行短路计算,也与C中的运算符相同,用于组合更原始的模式表达式。
pattern||pattern逻辑OR,与C中的运算符相同。它们进行短路计算,也与C中的运算符相同,用于组合更原始的模式表达式。
pattern ? pattern : pattern这个?:运算符类似于C中的同一运算符。如果第一个模式为真,则用于测试的模式为第二个模式,否则为第三个模式。第二和第三种模式中只有一种是可以执行的。
(pattern)
! pattern逻辑NOT,与C中的运算符相同。它们进行短路计算,也与C中的运算符相同,用于组合更原始的模式表达式。
pattern1, pattern2表达式的pattern1,pattern2形式称为范围模式。它匹配所有输入记录,从匹配pattern1的记录开始,一直到匹配pattern2的记录为止(包括pattern2)。它不与任何其他类型的模式表达式相结合。

5、正则表达式

表达式含义备注
cmatches the non-metacharacter c.
cmatches the literal character c.
.matches any character including newline.
^matches the beginning of a string.
$matches the end of a string.
[abc…]character list, matches any of the characters abc…
r1|r2matches either r1 or r2
r1r2concatenation: matches r1, and then r2.
r+matches one or more r’s.
r*matches zero or more r’s.
r?matches zero or one r’s.
®grouping: matches r.
r{n}
r{n,}
r{n,m}One or two numbers inside braces denote an interval expression. If there is one number in the braces, the preceding regular expression r is repeated n times. If there are two numbers separated by acomma, r is repeated n to m times. If there is one number followed by a comma, then r is repeated at least n times.
ymatches the empty string at either the beginning or the end of a word.
Bmatches the empty string within a word.
<matches the empty string at the beginning of a word.
>matches the empty string at the end of a word.
smatches any whitespace character.
Smatches any nonwhitespace character.
wmatches any word-constituent character (letter, digit, or underscore).
Wmatches any character that is not word-constituent.
`matches the empty string at the beginning of a buffer (string).
matches the empty string at the end of a buffer.
y、B、、s、s、w、`和’运算符特定于gawk;它们是基于GNU正则表达式库中的工具的扩展。

5、运算符

AWK中的运算符按优先级递减顺序为

       (...)       Grouping
       $           Field reference.
       ++ --       Increment and decrement, both prefix and postfix.
       ^           Exponentiation (** may also be used, and **= for the assignment operator).
       + - !       Unary plus, unary minus, and logical negation.
       * / %       Multiplication, division, and modulus.
       + -         Addition and subtraction.
       space       String concatenation.
       |   |&      Piped I/O for getline, print, and printf.
       < > <= >= != ==
                   The regular relational operators.
       ~ !~        正则表达式匹配,否定匹配。注意:不要在~或!~的左侧使用常量正则表达式(/foo/)。只在右手边使用一个。表达式/foo/~exp与($0~/foo/)~exp)具有相同的含义。            
       in          Array membership.
       &&          Logical AND.
       ||          Logical OR.
       ?:          The C conditional expression.  This has the form expr1 ? expr2 : expr3.  If expr1 is true, the value of the expression is expr2, otherwise it is expr3.  Only one of expr2 and expr3 is evaluated.
       = += -= *= /= %= ^=
                   Assignment.  Both absolute assignment (var = value) and operator-assignment (the other forms) are supported.

6、控制语句

   Control Statements
       The control statements are as follows:

              if (condition) statement [ else statement ]
              while (condition) statement
              do statement while (condition)
              for (expr1; expr2; expr3) statement
              for (var in array) statement
              break
              continue
              delete array[index]
              delete array
              exit [ expression ]
              { statements }
              switch (expression) {
              case value|regex : statement
              ...
              [ default: statement ]
              }

7、I/O语句

 I/O Statements
       The input/output statements are as follows:
       close(file [, how])   关闭文件、管道或协同处理。只有在将双向管道的一端封闭到co流程时,才应使用可选方式。它必须是字符串值,可以是“to”或“from”。
       getline               从下一个输入记录中设置$0;设置NF、NR、FNR。
       getline <file         文件集$0,来自文件的下一条记录;设置NF。
       getline var           从下一个输入记录中设置var;设置NR,FNR。
       getline var <file     文件的下一条记录中的文件集var。
       command | getline [var] 运行命令,将输出管道化为$0或var,如上所述。
       command |& getline [var] 以协同进程的形式运行命令,将输出管道化为$0或var,如上所述。协同过程是一个笨拙的扩展。(命令也可以是套接字。请参阅“特殊文件名”小节)

       next                 下一步停止处理当前输入记录。读取下一条输入记录,处理从AWK程序中的第一个模式开始。如果到达输入数据的末尾,则执行结束块(如果有)。
       nextfile              停止处理当前输入文件。读取的下一个输入记录来自下一个输入文件。FILENAME和argid更新,FNR重置为1,处理从AWK程序中的第一个模式。如果到达输入数据的末尾,则执行结束块(如果有)。
       print                 打印当前记录。输出记录以ORS变量的值终止。
       print expr-list       打印表达式列表打印表达式。每个表达式由OFS变量的值分隔。输出记录以ORS变量的值终止。
       printf fmt, expr-list Format and print.  打印fmt、expr列表格式和打印。参见下面的printf语句。
       printf fmt, expr-list >file  格式化并打印文件。
       system(cmd-line)      系统(cmd行)执行命令cmd行,并返回退出状态。(这在非POSIX系统上可能不可用。)
       fflush([file])        刷新与打开的输出文件或管道文件关联的所有缓冲区。如果文件丢失或为空字符串,则刷新所有打开的输出文件和管道。print和printf允许额外的输出重定向。
       print ... >> file   将输出附加到文件。
       print ... | command 在管道上写字。
       print ... |& command 将数据发送到协同进程或套接字。getline命令成功时返回1,文件结束时返回0,错误时返回-1。出现错误时,ERRNO包含一个描述问题的字符串。
       注意:如果无法打开双向套接字,则会将非致命错误返回给调用函数。如果在一个循环中使用管道、协进程或套接字来获取行,或从print或printf,则必须使用close()创建命令或套接字的新实例。当管道、插座或co进程返回EOF时,AWK不会自动关闭它们。
       

8、输出语句

   The printf Statement
       The AWK versions of the printf statement and sprintf() function (see below) accept the following conversion specification formats:

       %c      %c一个字符。如果用于%c的参数是数字,则会将其视为字符并打印出来。否则,将假定参数为字符串,并打印该字符串的唯一第一个字符。
       %d, %i  %d、 %i是十进制数(整数部分)。
       %e, %E  %e、 %e格式为[-]d的浮点数。dddddde[+-]dd.  The %E format uses E instead of e.
       %f, %F  格式为[-]ddd.dddddd。如果系统库支持,%F也可用。这类似于%f,但使用大写字母表示特殊的“非数字”和“无限”值。如果%F不可用,gawk将使用%F。
       %g, %G  使用%e或%f转换,以较短者为准,并抑制不重要的零。%G格式使用%E而不是%E。
       %o      无符号八进制数(也是整数)。
       %u      是无符号十进制数(同样是整数)。
       %s      这是一个字符串。
       %x, %X  无符号十六进制数(整数)。 The %X format uses ABCDEF instead of abcdef.
       %%      单个%字符;不转换任何参数。
       -      表达式应在其字段内左对齐。
       space  用于数字转换的空间,正值前面加空格,负值前面加减号。

       +      加号在宽度修饰符之前使用(见下文),表示始终为数字转换提供一个符号,即使要格式化的数据是正数。+将覆盖空间修改器。
#对某些控制字母使用“替代形式”。对于%o,请提供前导零。对于%x和%x,为非零结果提供前导0x或0x。对于%e、%e、%f和%f,结果始终包含
小数点。对于%g和%G,尾随零不会从结果中删除。

       0     前导的0(零)作为一个标志,指示输出应该用零而不是空格填充。这仅适用于数字输出格式。此标志仅在字段宽度比要打印的值宽。

9、awk 简单应用举例

awk [options] ‘commands’ filenames

awk [options] -f awk-script-file filenames

== options:

-F 定义输入字段分隔符,默认的分割符号是空格或者制表符

[root@localhost ~]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
[root@localhost ~]# awk '{print $1}' /etc/hosts    //获取hosts文件的第一列
127.0.0.1
::1
[root@localhost ~]# awk '{print $1}' /etc/passwd   //默认分隔符为空格或者t
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin

[root@localhost ~]# awk -F ":" '{print $1}' /etc/passwd  //指定分隔符为:
root
bin
daemon

== command:

BEGIN{ }{ }END{ }
行处理前(发生在读文件之前)行处理行处理后
通常用于定义一些变量,例如BEGIN{FS=‘:’;OFS=‘—’}
FS:字段分隔符
OFS:Out of Field Separator,输出字段分隔符
[root@localhost ~]# awk 'BEGIN{print 3}{print "ok"}END{print "------"}'  //后面没有文件依然有输出
3
[root@localhost ~]# awk 'BEGIN{print 3}{print "ok"}END{print "------"}' /etc/hosts
3      //行处理前
ok     //逐行处理
ok     //逐行处理
------ //行处理后
[root@localhost ~]# awk 'BEGIN{FS=":"}{print $1}END{print "------"}' /etc/passwd //FS:字段分隔符
root
bin
daemon
[root@localhost ~]# awk 'BEGIN{FS=":";OFS="---"}{print $1,$2}END{print "------"}' /etc/passwd  // OFS:Out of Field Separator,输出字段分隔符
root---x
bin---x
daemon---x

== awk命令格式

awk ‘pattern’ filename 实例:awk ‘/root/’ /etc/passwd 正则表达式

awk ‘{action}’ filename 实例:awk ‘{print $1}’ /etc/passwd action模式

awk ‘pattern {action}’ filename 实例:awk ‘/root/{print $1}’ /etc/passwd 两种模式

​ 实例:awk 'BEGIN{FS=“:”} ‘/root/{print $1}’ /etc/passwd

command | awk ‘pattern {action}’ 实例:df -P |grep ‘/’ |awk ‘$4>25000{print $4}’

[root@localhost ~]# awk -F: '/root/'  /etc/passwd 
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@localhost ~]# awk -F: '{print $1,$3}'  /etc/passwd 
root 0
bin 1
//原理解读:1、awk使用一行作为输入,并将这一样赋给内部变量$02、然后行被``被分解成字段,每个字段存储在已编号的变量中,从$1开始,最多可以到100个字段
          3、awk是如何知道用空格还是其他的分割符来分割字段呢?因为有一个内部变量`FS`来确定字段分隔符。
          4、awk打印字段时,将使用print函数打印。awk在打印字段之间加上空格。因为$1$3之间有一个逗号。
          逗号比较特殊,他映射了另外一个内部变量`OFS,OFS`默认分隔符是空格。
[root@localhost ~]# awk '/root/{print $1}'  /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@localhost ~]# awk 'BEGIN{FS=":"}/root/{print $1}'  /etc/passwd 
root
operator
[root@localhost ~]# df -P
文件系统        1024-块    已用    可用 配额 挂载点
/dev/sda3      18555904 9297296 9258608  51% /
devtmpfs        1917956       0 1917956   0% /dev
tmpfs           1932652       0 1932652   0% /dev/shm
tmpfs           1932652    9344 1923308   1% /run
tmpfs           1932652       0 1932652   0% /sys/fs/cgroup
/dev/sda1        303780  160340  143440  53% /boot
tmpfs            386532      52  386480   1% /run/user/1000
tmpfs            386532       0  386532   0% /run/user/0
/dev/loop0      4414592 4414592       0 100% /mnt
[root@localhost ~]# df -P |grep '/' |awk '$4>25000{print $4}'
9258608
1917956
1932652
1923308
1932652
143440
386480
386532
``

10、AWK经典用法示例

#删除temp文件的重复行
awk '!($0 in array) { array[$0]; print }' temp
#查看最长使用的10个unix命令
awk '{print $1}' ~/.bash_history | sort | uniq -c | sort -rn | head -n 10
#查看机器的ip列表
ifconfig -a | awk '/Bcast/{print $2}' | cut -c 5-19
#查看机器的每个远程链接机器的连接数
netstat -antu | awk '$5 ~ /[0-9]:/{split($5, a, ":"); ips[a[1]]++} END {for (ip in ips) print ips[ip], ip | "sort -k1 -nr"}'
#查看某个进程打开的socket数量
ps aux | grep [process] | awk '{print $2}' | xargs -I % ls /proc/%/fd | wc -l
#查看无线网络的ip
sudo ifconfig wlan0 | grep inet | awk 'NR==1 {print $2}' | cut -c 6-
#批量重命名文件
find . -name '*.jpg' | awk 'BEGIN{ a=0 }{ printf "mv %s name%01d.jpgn", $0, a++ }' | bash
#查看某个用户打开的文件句柄列表
for x in `ps -u 500 u | grep java | awk '{ print $2 }'`;do ls /proc/$x/fd|wc -l;done
#计算文件temp的第一列的值的和
awk '{s+=$1}END{print s}' temp
#查看最常用的命令和使用次数
history | awk '{if ($2 == "sudo") a[$3]++; else a[$2]++}END{for(i in a){print a[i] " " i}}' |  sort -rn | head
#查找某个时间戳的文件列表
cp -p `ls -l | awk '/Apr 14/ {print $NF}'` /usr/users/backup_dir
#格式化输出当前的进程信息
ps -ef | awk -v OFS="n" '{ for (i=8;i<=NF;i++) line = (line ? line FS : "") $i; print NR ":", $1, $2, $7, line, ""; line = "" }'
#查看输入数据的特定位置的单个字符
echo "abcdefg"|awk 'BEGIN {FS="''"} {print $2}'
#打印行号
ls | awk '{print NR "t" $0}'
#打印当前的ssh 客户端
netstat -tn | awk '($4 ~ /:22s*/) && ($6 ~ /^EST/) {print substr($5, 0, index($5,":"))}'
#打印文件第一列不同值的行
awk '!array[$1]++' file.txt
#打印第二列唯一值
awk '{ a[$2]++ } END { for (b in a) { print b } }' file
#查看系统所有分区
awk '{if ($NF ~ "^[a-zA-Z].*[0-9]$" && $NF !~ "c[0-9]+d[0-9]+$" && $NF !~ "^loop.*") print "/dev/"$NF}'  /proc/partitions
#查看2到100所有质数
for num in `seq 2 100`;do if [ `factor $num|awk '{print $2}'` == $num ];then echo -n "$num ";fi done;echo
#查看第3到第6行
awk 'NR >= 3 && NR <= 6' /path/to/file
#逆序查看文件
awk '{a[i++]=$0} END {for (j=i-1; j>=0;) print a[j--] }'
#打印99乘法表
seq 9 | sed 'H;g' | awk -v RS='' '{for(i=1;i<=NF;i++)printf("%dx%d=%d%s", i, NR, i*NR, i==NR?"n":"t")}'