-
linux awk命令详解
2019-09-11 21:17:21 -
Linux awk命令详解
2017-08-05 10:09:03Linux awk命令详解本文转自:http://blog.csdn.net/SeeTheWorld518/article/details/48630271
awk :适用程序,一种unix工具
就是一个强大的文本分析工具,相对于grep查找、sed的编辑,awk在对数据分析并生成报告的时候,显得尤为强大。简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种处理。- awk是用来操作数据和产生报表的一种编程语言。数据可能来自标准输入、一个或多个文件或一个进程的输出等。awk可以用在命令行里进行简单操作,也可应用到较大的应用程序中。
- awk是一门编程语法,作为unix工具来使用简化了很多,但是仍然有许多编程语言的特性,可以对目标进行一系列的处理。
-
如果抛出awk的BEGIN和END,对文件的每行,awk都分两个阶段处理:
1、读取该行内容,分配临时寄存器,分配域名等操作;
2、对域做各种处理并输出; -
awk基本用途
1、简单输出,如 awk ‘{print 1,NF}’ — print的规则
2、作为分隔符使用
单字符分隔符:打印系统中用户名和其他使用shell类型
单字符分隔符,管道连续使用awk:打印nginx日志中的访问目录。
多字符分隔符:抓取apache详细版本
多字符多个分隔符:截取ip地址
正则分隔符:截取ip地址
[root@admin test]# ls -l total 16 -rw-r--r--. 1 root root 0 Jun 15 11:03 aa.jpg -rw-r--r--. 1 root root 12 Jun 15 10:48 ls.jpg -rw-r--r--. 1 root root 200 Jun 15 11:31 result.jpg -rw-r--r--. 1 root root 0 Jun 15 11:04 right.jpg drwxr-xr-x. 2 root root 4096 Jun 20 06:39 sd.ex -rw-r--r--. 1 root root 49 Jun 15 11:04 wrong.jpg
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
通过awk打印出第一列:
[root@admin test]# ls -l | awk '{print $1}' total -rw-r--r--. -rw-r--r--. -rw-r--r--. -rw-r--r--. drwxr-xr-x. -rw-r--r--.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
打印前两列,也就是前两个域:
[root@admin test]# ls -l | awk '{print $1,$2}' total 16 -rw-r--r--. 1 -rw-r--r--. 1 -rw-r--r--. 1 -rw-r--r--. 1 drwxr-xr-x. 2 -rw-r--r--. 1
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
在awk中,抛开BEGIN和END不看,’{}’ 这是一个固定写法。
$ : 符号表示域,域之间通过默认的分隔符 空格 分开,如果有多个空格就会变成一个空格,第一个域为$1,第二个为$2等…打印最后一列:
[root@admin test]# ls -l | awk '{print $NF}' 16 aa.jpg ls.jpg result.jpg right.jpg sd.ex wrong.jpg
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
$NF : 就代表最后一列的意思。
如果想打印倒数第二列,则使用$(NF -1)。[root@admin test]# ls -l | awk '{print $(NF - 1)}' total 11:03 10:48 11:31 11:04 06:39 11:04
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
-F :参数-F是改变awk的默认分隔符,可以支持正则表达式。
[root@admin test]# ls -l total 16 -rw-r--r--. 1 root root 0 Jun 15 11:03 aa.jpg -rw-r--r--. 1 root root 12 Jun 15 10:48 ls.jpg -rw-r--r--. 1 root root 200 Jun 15 11:31 result.jpg -rw-r--r--. 1 root root 0 Jun 15 11:04 right.jpg drwxr-xr-x. 2 root root 4096 Jun 20 06:39 sd.ex -rw-r--r--. 1 root root 49 Jun 15 11:04 wrong.jpg
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
awk默认的分隔符是 空格,空格前一列就是$1,后面是$2,$3…..
当我们改变默认分隔符为 分号 “:”时,打印一下结果:[root@admin test]# ls -l | awk -F":" '{print $NF}' total 16 03 aa.jpg 48 ls.jpg 31 result.jpg 04 right.jpg 39 sd.ex 04 wrong.jpg
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
通过-F 参数改变默认分隔符,以及其支持正则表达式的特性,精确的抽出ifconfig 文件中的ip地址。
#精确的抽取ip地址 [root@admin test]# ifconfig | grep "inet addr" | awk -F "addr:| *" '{print $4}' 192.168.1.6 127.0.0.1
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
分析:
grep "inet addr" 表示先抽取出含有ip的那行,然后通过管道交给awk去处理 -F "addr:| *" :表示该变默认分隔符为addr:或者连续多个空格 $4 :表示改变默认分隔符以后,ip地址在第4个域。
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
用grep实现抽取ip :
[root@admin home]# ifconfig | egrep -o "[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*" 192.168.1.6 192.168.1.255 255.255.255.0 127.0.0.1 255.0.0.0
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
然后在用head和tail抽取想要的ip即可。
使用sed实现抽取ip
[root@admin home]# ifconfig |grep "inet addr" | sed 's/inet addr://' | sed 's/Bcast.*//' | head -1 192.168.1.6 或者: [root@admin home]# ifconfig |grep "inet addr" | sed 's/^.*addr://;s/ *.*//' | head -1 192.168.1.6
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
awk匹配打印
注:需要匹配的内容是写在{}外面的,通过//来体现匹配。
匹配打印实际上是文件每行读取的时候做的处理。1、整行中匹配内容
awk '/sth/{print $1}' ---打印匹配sth的行的第一个域,这是对整行进行操作 awk '!/sth/{print $1}' ---打印不匹配sth的行的第一个域
- 1
- 2
- 3
- 1
- 2
- 3
如匹配打印sd关键字:
[root@admin test]# ls aa.jpg ls.jpg result.jpg right.jpg sd.ex wrong.jpg [root@admin test]# ls | awk '/sd/{print $1}' sd.ex
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
2、域匹配内容
匹配某个文件中以默认分隔符分隔的$1域中含有关键字sth的行,然后打印出第一个域,命令如下:awk '$1~/sth/{print $1}'
- 1
- 1
3、改变awk中的默认分隔符
如打印出passwd文件中,以冒号 : 分隔的第一个域中含有关键字wcx行的第一个域:[root@admin etc]# cat passwd | awk -F":" '$1~/wcx/{print $1}' wcx
- 1
- 2
- 3
- 1
- 2
- 3
awk判断打印
判断打印实际上是文件每行读取后做的处理。
格式例如:awk '{if($1=="wcx")print $1}'
- 1
- 1
if 判断必须是进入某一行以后才能做的,所以必须是在花括号{} 里面。而模式匹配是先匹配到内容的行才能进行下一步操作,所以模式匹配实在花括号{}外边。
[root@admin etc]# cat ./passwd | awk -F ":" '{if($1 == "wcx")print} wcx:x:501:501::/home/wcx:/bin/bash
- 1
- 2
- 3
- 1
- 2
- 3
上面命令中,如果passwd文件中,以冒号分隔的第一个域==”wcx”,那么就打印出来,这是等于判断,所以只有wcx的行能出来。
BEGIN和END
在Unix awk中两个特别的表达式,BEGIN和END,这两者都可用于pattern中(参考前面的awk语法),提供BEGIN和END的作用是给程序赋予初始状态和在程序结束之后执行一些扫尾的工作。
任何在BEGIN之后列出的操作(在{}内)将在Unix awk开始扫描输入之前执行,而END之后列出的操作将在扫描完全部的输入之后执行。因此,通常使用BEGIN来显示变量和预置(初始化)变量,使用END来输出最终结果。awk的数组
有一个awk.txt文件,其内容如下:
[root@admin home]# cat awk.txt kk kekea jj d32 jame 23 sr sr kk jame wcx jame
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
统计一下awk.txt文件中每个人名出现的次数:
[root@admin home]# cat awk.txt | awk '{a[$1]++}END{for (i in a)print i,a[i]}' wcx 1 jj 1 kk 2 sr 2 jame 3
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
解题思路分析:
{a[$1]++} :awk开始扫描管道传过来的内容,但是么有存储功能,现在我们需要计算每个人名出现的额次数,所以需要把扫描到的相同的人名分别存储起来,这时候就必须用数组,并且这里的数组都是hash数组,就是键值对的数组,这里的键—对应的就是对应域中的人名,如kk,值 — 对应的就是kk这个人名出现的次数。数组a中的下标$1代表的是第一个域中列名,如wcx。awk开始逐行扫描,每扫到一个相同的人名,对应的hash数组里的值就+1,如a[kk]++,直到扫到文件的结尾。(注:数组的默认值为空,如果要做++操作了,就会把里的值变成0)
END : END之后列出的操作将在Unix awk开始扫描完全部的输入之后执行。上面扫描完以后,就开始执行END后面的操作了。
{for (i in a)print i,a[i]} :利用for循环去遍历刚刚产生的hash数组,然后打印出数组下标所代表的值,也就是人名以及对数组中的值,也就是对应人名出现的次数。这里的i,就代表数组的下标,也就是域中的人名,如kk。
awk输出分隔符
awk默认的输出分隔符也是空格,如果想改变默认输出分隔符怎么做?
[root@admin home]# cat awk.txt | awk '{print $1,$2}' kk kekea jj d32 jame 23 sr 234 sr edr kk 23 jame rt wcx 88 jame 34
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
运行结果看出,打印时,$1和$2间加了逗号以后,输出的文本中域间就都是用空格隔开的。
如果我不加逗号,改为加一串别的字符时,输出后就以加入的字符作为分隔符了。如:[root@admin home]# cat awk.txt | awk '{print $1"--"$2"BB"}' kk--kekeaBB jj--d32BB jame--23BB sr--234BB sr--edrBB kk--23BB jame--rtBB wcx--88BB jame--34BB
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
通过awk批量修改扩展名
[root@admin test]# ls aa.jpg ls.jpg result.jpg right.jpg wrong.jpg
- 1
- 2
- 3
- 1
- 2
- 3
将test目录下的以.jpg结尾的文件改成.txt结尾的文件:
[root@admin test]# ls | awk -F "." '{print "mv "$1"."$2" "$1".txt"}'|sh [root@admin test]# ls aa.txt ls.txt result.txt right.txt wrong.txt 或者: [root@admin test]# ls | awk -F "." '{print "mv "$0" "$1".txt"}' | sh #$0表示整行的内容
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
思路分析,同样改名也是需要构造mv a.txt a.jpg这样类似的语句的,这就用到了上面讲的输出时修改默认分隔符的操作了。构造出的mv语句再传给sh去执行就可以实现改名的操作。
-
linux awk 命令详解
2019-07-22 09:55:09Linux awk命令详解 awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再...Linux awk命令详解
awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。
使用方法 : awk '{pattern + action}' {filenames}
尽管操作可能会很复杂,但语法总是这样,其中 pattern 表示 AWK 在数据中查找的内容,而 action 是在找到匹配内容时所执行的一系列命令。花括号({})不需要在程序中始终出现,但它们用于根据特定的模式对一系列指令进行分组。 pattern就是要表示的正则表达式,用斜杠括起来。
awk语言的最基本功能是在文件或者字符串中基于指定规则浏览和抽取信息,awk抽取信息后,才能进行其他文本操作。完整的awk脚本通常用来格式化文本文件中的信息。通常,awk是以文件的一行为处理单位的。awk每接收文件的一行,然后执行相应的命令,来处理文本。
awk内置变量
1
2
3
4
5
6
7
8
9
10
11
12
ARGC 命令行参数个数
ARGV 命令行参数排列
ENVIRON 支持队列中系统环境变量的使用
FILENAME
awk
浏览的文件名
FNR 浏览文件的记录数
FS 设置输入域分隔符,等价于命令行 -F选项
NF 浏览记录的域的个数
NR 已读的记录数
OFS 输出域分隔符
ORS 输出记录分隔符
RS 控制记录分隔符
$0变量是指整条记录。$1表示当前行的第一个域,$2表示当前行的第二个域,......以此类推。
1
$NF是number finally,表示最后一列的信息,跟变量NF是有区别的,变量NF统计的是每行列的总数
常用的命令展示
awk擅长列输出
搜索/etc/passwd有root关键字的所有行
1
awk
'/root/'
/etc/passwd
【这种是pattern的使用,匹配了pattern(这里是root)的行才会执行action(没有指定action,默认输出每行的内容)】
搜索/etc/passwd有root关键字的所有行,并显示对应的shell
1
awk
-F:
'/root/ {print $7}'
/etc/passwd
统计/etc/passwd:文件名,每行的行号,每行的列数,对应的完整行内容:
1
awk
-F
':'
'{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:"$0}'
/etc/passwd
使用printf替代print,可以让代码更加简洁,易读
1
awk
-F:
'{printf ("filename:%10s, linenumber:%3s,column:%3s,content:%3f\n",FILENAME,NR,NF,$0)}'
/etc/passwd
打印/etc/passwd/的第二行信息
1
awk
-F:
'NR==2{print "filename: "FILENAME, $0}'
/etc/passwd
awk的过滤使用方法
1
ls
-lF |
awk
'/^d/'
1
awk
-F
":"
'{print $1}'
/etc/passwd
1
awk
-F
":"
'{print $NF}'
/etc/passwd
1
awk
-F
":"
'{print $NF-1}'
/etc/passwd
1
awk
-F
":"
'{if(NR<31 && NR >12) print $1}'
/etc/passwd
多分隔符的使用:
1
2
[root@localhost ftl]
# awk -F "[/]" 'NR == 4 {print $0,"\n",$1}' /etc/passwd
这里以/为分隔符,多个分隔符利用[]然后在里面写分隔符即可
1
[root@localhost ftl]
# cat /etc/passwd | awk -F: 'BEGIN{print "name, shell"} {print $1,$NF} END{print "hello world"}'
查看最近登录最多的IP信息
1
[root@localhost ftl]
# last | awk '{S[$3]++} END{for(a in S ) {print S[a],a}}' |uniq| sort -rh
利用正则过滤多个空格
1
[root@localhost ~]
# ifconfig |grep eth* | awk -F '[ ]+' '{print $1}'<br><br>
awk编程--变量和赋值
除了awk的内置变量,awk还可以自定义变量, awk中的循环语句同样借鉴于C语言,支持while、do/while、for、break、continue,这些关键字的语义和C语言中的语义完全相同。
统计某个文件夹下的大于100k文件的数量和总和
1
2
ls
-l|
awk
'{if($5>100){count++; sum+=$5}} {print "Count:" count,"Sum: " sum}'
【因为
awk
会轮询统计,所以会显示整个过程】
ls
-l|
awk
'{if($5>100){count++; sum+=$5}} END{print "Count:" count,"Sum: " sum}'
【天界END后只显示最后的结果】
1
<strong>备注:<
/strong
>count是自定义变量。之前的action{}里都是只有一个print,其实print只是一个语句,而action{}可以有多个语句,以;号隔开
统计显示/etc/passwd的账户
1
2
3
awk
-F:
'{count++;} END{print count}'
/etc/passwd
cat
/etc/passwd
|
wc
-l
awk
-F
':'
'BEGIN {count=0;} {name[count] = $1;count++;}; END{for (i = 0; i < NR; i++) print i, name[i]}'
/etc/passwd
-
Linux awk命令详解
2010-08-26 20:18:00