linux三剑客(grep、sed、awk)学习

1.前言

本文是本人通过自己的理解以及按照自己的方式进行整理,仅仅用于记录自己的学习过程,方便后续查看。

2.概述

  • grep:文本过滤器,如果仅仅是过滤文本,可使用grep,其效率要比其他的高很多

  • sed:Stream EDitor,流编辑器,默认只处理模式空间,不处理原数据,如果你处理的数据是针对行进行处理的,可以使用sed

  • awk:报告生成器,格式化以后显示。如果对处理的数据需要生成报告之类的信息,或者你处理的数据是按列进行处理的,最好使用awk。简言而之:

       - grep擅长查找功能
       - sed擅长取行和替换 
       - awk擅长取列。
    

3.正则表达式

最简单的情况下,一个正则表达式看着就是一个普通的查找串。例如,正则表达式”file”中没有包含任何元字符,它可以匹配”file”和”file1”等字符串,但是不能匹配”File”。
要想真正的用好正则表达式,正确的理解元字符是最重要的事情。下表列出了常用元字符和对它们的一个简短的描述。

元字符功能描述
^匹配行首表示以某个字符开头
$匹配行尾表示以某个字符结尾
^$空行的意思表示空行的意思
.匹配任意单个字符表示任意一个字符
*匹配0或多个正好在它之前的那个字符表示重复的任意多个字符
+匹配 1 或多个正好在它之前的那个字符
?匹配 0 或 1 个正好在它之前的那个字符
|将两个匹配条件进行逻辑 “或”(or)运算
\转义符用来将后面所跟的元字符当作普通的字符来进行匹配
[]匹配括号中的任何一个字符表示过滤括号内的字符
X{m}匹配字符 X出现 m 次就是统计前面X出现的次数
X{m,}匹配字符 X 出现 最少 m 次就是统计前面X出现的次数
X{m,n}匹配字符 X 出现 m—n 次就是统计前面X出现的次数

4.grep

Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹 配的行打印出来。grep全称是Global Regular Expression Print,表示全局正则表达式版本,它的使用权限是所有用户。

4.1语法格式

grep [OPTION]... PATTERN [FILE]...

选项说明

Regexp selection and interpretation描述
-E, --extended-regexpPATTERN is an extended regular expression (ERE)
-F, --fixed-stringsPATTERN is a set of newline-separated fixed strings
-G, --basic-regexpPATTERN is a basic regular expression (BRE)
-P, --perl-regexpPATTERN is a Perl regular expression
-e, --regexp=PATTERNuse PATTERN for matching
-f, --file=FILEobtain PATTERN from FILE
-i, --ignore-caseignore case distinctions
-w, --word-regexpforce PATTERN to match only whole words
-x, --line-regexpforce PATTERN to match only whole lines
-z, --null-dataa data line ends in 0 byte, not newline
Miscellaneous描述
-s, --no-messagessuppress error messages(预制错误信息)
-v, --invert-matchselect non-matching lines(选择非匹配行)
-V, --versiondisplay version information and exit
–helpdisplay this help text and exit
Output control描述
-m, --max-count=NUMstop after NUM matches
-b, --byte-offsetprint the byte offset with output lines
-n, --line-numberprint line number with output lines
–line-bufferedflush output on every line
-H, --with-filenameprint the file name for each match
-h, --no-filenamesuppress the file name prefix on output
–label=LABELuse LABEL as the standard input file name prefix
-o, --only-matchingshow only the part of a line matching PATTERN
-q, --quiet, --silentsuppress all normal output
–binary-files=TYPEassume that binary files are TYPE;TYPE is ‘binary’, ‘text’, or ‘without-match’
-a, --textequivalent to --binary-files=text
-Iequivalent to --binary-files=without-match
-d, --directories=ACTIONhow to handle directories;
ACTION is ‘read’, ‘recurse’, or ‘skip’
-D, --devices=ACTIONhow to handle devices, FIFOs and sockets;ACTION is ‘read’ or ‘skip’
-r, --recursivelike --directories=recurse
-R, --dereference-recursivlikewise, but follow all symlinks
–include=FILE_PATTERNsearch only files that match FILE_PATTERN
–exclude=FILE_PATTERNskip files and directories matching FILE_PATTERN
–exclude-from=FILEskip files matching any file pattern from FILE
–exclude-dir=PATTERNdirectories that match PATTERN will be skipped.
-L, --files-without-matchprint only names of FILEs containing no match
-l, --files-with-matchesprint only names of FILEs containing matches
-c, --countprint only a count of matching lines per FILE
-T, --initial-tabmake tabs line up (if needed)
-Z, --nullprint 0 byte after FILE name
Context control描述
-B, --before-context=NUMprint NUM lines of leading context(打印以文本起始的NUM行)
-A, --after-context=NUMprint NUM lines of trailing context(打印以文本结尾的NUM行)
-C, --context=NUMprint NUM lines of output context
-NUMsame as --context=NUM(打印输出文本NUM行)
–group-separator=SEPuse SEP as a group separator
–no-group-separatoruse empty string as a group separator
–color[=WHEN],
–colour[=WHEN]use markers to highlight the matching strings;WHEN is ‘always’, ‘never’, or ‘auto’
-U, --binarydo not strip CR characters at EOL (MSDOS/Windows)
-u, --unix-byte-offsetsreport offsets as if CRs were not there (MSDOS/Windows)

4.2示例

1)grep 'test' d*  #显示所有以d开头的文件中包含 test的行
2)grep ‘test’ aa bb cc    #显示在aa,bb,cc文件中包含test的行
3)grep ‘[a-z]\{5\}’ aa   #显示所有包含每行字符串至少有5个连续小写字符的字符串的行
4)grep magic /usr/src  #显示/usr/src目录下的文件(不含子目录)包含magic的行
5)grep -r magic /usr/src  #显示/usr/src目录下的文件(包含子目录)包含magic的行
6)grep -w pattern files :只匹配整个单词,而不是字符串的一部分(如匹配’magic’,而不是’magical’)

5.sed

sed 是一种在线编辑器,它一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出。Sed主要用来自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等。
awk 有 3 个不同版本: awk、nawk 和 gawk,未作特别说明,一般指 gawk,gawk 是 AWK 的 GNU 版本

5.1语法格式

sed [options] [sed -commands][input -file]
sed [选项]  【sed命令】 【输入文件】

选项说明

option[选项]描述
-n使用安静(silent)模式。在一般 sed 的用法中,所有来自 STDIN的资料一般都会被列出到萤幕上。但如果加上 -n 参数后,则只有经过sed 特殊处理的那一行(或者动作)才会被列出来。
-e一行命令语句可以执行多条sed命令
-f选项后面可以接sed脚本的文件名
-r使用扩展正则表达式,默认情况sed只识别基本正则表达式
-i直接修改文件内容,而不是输出到终端,如果不使用-i选项sed软件只是修改在内存中的数据,并不会影响磁盘上的文件
commands[sed命令]描述
a新增, a 的后面可以接字串,追加文本到指定行后,支持使用\n实现多行追加
i插入, i 的后面可以接字串,在指定行前添加一行或多行文本
c取代, 用新行取代旧行,c 的后面可以接字串,这些字串可以取代 n1,n2 之间的行!
d删除,因为是删除啊,所以 d 后面通常不接任何咚咚;
p列印,亦即将某个选择的资料印出。通常 p 会与参数 sed -n 一起运作
P打印模式空间的内容,直到遇到换行符\n结束操作
s///查找替换,支持使用其它分隔符,s@@@,s###,替换标记: 1.g 行内全局替换2.p 显示替换成功的行3.w /PATH/TO/SOMEFILE 将替换成功的行保存至文件中
D删除模式空间的部分内容,直到遇到换行符\n结束操作,与多行模式相关
h把模式空间的内容复制到保持空间
H把模式空间的内容追加到保持空间
g把保持空间的内容复制到模式空间
G把保持空间的内容追加到模式空间
x交换模式空间和保持空间的内容
l打印不可见的字符
n清空模式空间的内容并读入下一行
N不清空模式空间,并读取下一行数据并追加到模式空间
q退出Sed
r从指定文件读取数据
w另存,把模式空间的内容保存到文件中
y根据对应位置转换字符
:label定义一个标签
b label执行该标签后面的命令
t如果前面的命令执行成功,那么就跳转到t指定的标签处,继续往下执行后续命令。否则,仍然继续正常的执行流程
特殊字符描述
!对指定行以外的所有行应用命令
=打印当前行行号
~“First~step”表示从First行开始,以步长Step递增
&代表被替换的内容
:实现一行命令语句可以执行多条sed命令
{}对单个地址或地址范围执行批量操作
+地址范围中用到的符号,做加法运算

sed软件可以对单行或多行文本进行处理。如果在sed命令前面不指定地址范围,那么默认会匹配所有行。
用法:n1[,n2]{sed -commands}
地址用逗号分隔开,n1,n2可以用数字,正则表达式,或者二者的组合表示

指定执行的地址范围描述
不给地址对全文进行处理
单地址#: 指定的行,$:最后一行,/pattern/:被此处模式所能够匹配到的每一行
地址范围#,#;#,+#;/pat1/,/pat2/; `#,/pat1/
~步进,1~2 奇数行,2~2 偶数行
例子描述
10{sed-commands}对第10行操作
10,20{sed-commands}对10到20行操作,包括第10,20行
10,+20{sed-commands}对10到30(10+20)行操作,包括第10,30行
1~2{sed-commands}对1,3,5,7…行操作
10,${sed-commands}对10到最后一行($代表最后一行)操作,包括第10行
/chensiqi/{sed-commands}对匹配chensiqi的行操作
/chensiqi/,/Alex/{sed-commands}对匹配chensiqi的行到匹配Alex的行操作
/chensiqi/,${sed-commands}对匹配chensiqi的行到最后一行操作
/chensiqi/,10{sed-commands}对匹配chensiqi的行到第10行操作,注意:如果前10行没有匹配到chensiqi,sed软件会显示10行以后的匹配chensiqi的行
1,/Alex/{sed-commands}对第1行到匹配Alex的行操作
/chensiqi/,+2{sed-commands}对匹配chensiqi的行到其后的2行操作

5.2示例

5.2.1增

这里我们需要用到2个sed命令,分别是:
“a”:追加文本到指定行后,记忆方法:a的全拼是apend,意思是追加。
“i“:插入文本到指定行前,记忆方法:i的全拼是insert,意思是插入。
5.2.1.1单行增

# sed '2a 106,dandan,CSO' person.txt
101,chensiqi,CEO
102,zhangyang,CTO
106,dandan,CSO   #这就是新增那句
103,Alex,COO
104,yy,CFO
105,feixue,CIO

5.2.1.2多行增

# sed '2a 106,dandan,CSO\n107,bingbing,CCO' person.txt 
101,chensiqi,CEO
102,zhangyang,CTO
106,dandan,CSO  #同时追加多行
107,bingbing,CCO  #同时追加多行
103,Alex,COO
104,yy,CFO
105,feixue,CIO
EOF

5.2.2删

# sed '2d' person.txt   --指定删除第2行的文本
# sed 'd' person.txt  ---删除这个文件的所有内容
# sed '2,5d' person.txt  ---指定删除第2行到第5行的内容
# sed '/zhangyang/d' person.txt   ----在sed软件中,使用正则的格式和awk一样,使用2个”/“包含指定的正则表达式,即“/正则表达式/”。
# sed '/chensiqi/,/Alex/d' person.txt   ---这是正则表达式形式的多行删除,也是以逗号分隔2个地址,最后结果是删除包含“chensiqi”的行到包含“Alex”的行
# sed '3,$d' person.txt  --删除第3行到最后一行的文本,包含第3行和最后一行
# sed '1~2d' person.txt  --“1~2”这是指定行数的另一种格式,从第1行开始以步长2递增的行(1,3,5),因此删掉第1,3,5行,即所有的奇数行
# sed '1,+2d' person.txt   --这其实是做个加法运算,‘1,+2d’==>删除第1行到第3(1+2)行的文本。
# sed '2,3!d' person.txt  --在地址范围“2,3”后面加上“!”,如果不加“!”表示删除第2行和第3行,结果如下面的例子所示,然后加上“!”的结果就是除了第2行和第3行以外的内容都删除,这个方法可以作为显示文件的第2,3行题目的补充方法。

5.2.3改
5.2.3.1按行改

首先说一下按行替换,这个功能用的很少,所以大家了解即可。这里用到的sed命令是:
“c”:用新行取代旧行,记忆方法:c的全拼是change,意思是替换。

# sed '2c 106,dandan,CSO' person.txt  --使用sed命令c将原来第2行“102,zhangyang,CTO”替换成“106,dandan,CSO”,整行替换

5.2.3.2文本替换

•接下来说的这个功能,有工作经验的同学应该非常的熟悉,因为使用sed软件80%的场景就是使用替换功能。
•这里用到的sed命令,选项:
“s”:单独使用–>将每一行中第一处匹配的字符串进行替换==>sed命令
“g”:每一行进行全部替换–>sed命令s的替换标志之一(全局替换),非sed命令。
“-i”:修改文件内容–>sed软件的选项,注意和sed命令i区别
sed软件替换模型

sed -i ‘s/目标内容/替换内容/g’ chensiqi.log
sed -i ‘s#目标内容#替换内容#g’

观察特点

1,两边是引号,引号里面的两边分别为s和g,中间是三个一样的字符/或#作为定界符。字符#能在替换内容包含字符/有助于区别。定界符可以是任意字符如:或|等,但当替换内容包含定界符时,需要转义:或|.经过长期实践,建议大家使用#作为定界符。
2,定界符/或#,第一个和第二个之间的就是被替换的内容,第二个和第三个之间的就是替换后的内容。
3,s#目标内容#替换内容#g ,“目标内容”能用正则表达式,但替换内容不能用,必须是具体的。因为替换内容使用正则的话会让sed软件无所适从,它不知道你要替换什么内容。
4,默认sed软件是对模式空间(内存中的数据)操作,而-i选项会更改磁盘上的文件内容。
5.2.3.3分组替换()和\1的使用说明

sed软件的()的功能可以记住正则表达式的一部分,其中,\1为第一个记住的模式即第一个小括号中的匹配内容,\2第二个记住的模式,即第二个小括号中的匹配内容,sed最多可以记住9个。

例:echo "I am chensiqi teacher."如果想保留这一行的单词chensiqi,删除剩下部分,使用圆括号标记想保留的部分。

[root@chensiqi1 ~]# echo "I am chensiqi teacher." | sed 's#^.*am \([a-z]\+\) tea.*$#\1#g'
chensiqi

[root@chensiqi1 ~]# echo "I am chensiqi teacher." | sed -r 's#^.*am ([a-z]+) tea.*$#\1#g'
chensiqi

[root@chensiqi1 ~]# echo "I am chensiqi teacher." | sed -r 's#I (.*) (.*) teacher.#\1\2#g'
amchensiqi

命令说明:
sed如果不加-r后缀,那么默认不支持扩展正则表达式,需要\符号进行转义。小括号的作用是将括号里的匹配内容进行分组以便在第2和第3个#号之间进行sed的反向引用,\1代表引用第一组,\2代表引用第二组

6.2.3.5 4特殊符号&代表被替换的内容

这是一个特殊技巧,在适合的场景使用特别方便。下面用特殊符号“&”与分组替换一起使用,进行对比

[root@chensiqi1 ~]# sed -r 's#(.*),(.*),(.*)#& ----- \1 \2 \3#' person.txt 
101,chensiqi,CEO ----- 101 chensiqi CEO
102,zhangyang,CTO ----- 102 zhangyang CTO
103,Alex,COO ----- 103 Alex COO
104,yy,CFO ----- 104 yy CFO
105,feixue,CIO ----- 105 feixue CIO

命令说明:
    1,这里将分组替换和&符号放在一起对比
    2,命令中的分组替换使用了3个小括号,每个小括号分别代表每一行以逗号作为分隔符的每一列。
    3,上面命令的&符号代表每一行,即模型中‘s#目标内容#替换内容#g’的目标内容。

5.2.4查
5.2.4.1 按行查询

[root@chensiqi1 ~]# sed '2p' person.txt 
101,chensiqi,CEO
102,zhangyang,CTO
102,zhangyang,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO
[root@chensiqi1 ~]# sed -n '2p' person.txt 
102,zhangyang,CTO

命令说明:选项-n取消默认输出,只输出匹配的文本,大家只需要记住使用命令p必用选项-n。

[root@chensiqi1 ~]# sed -n '2,3p' person.txt 
102,zhangyang,CTO
103,Alex,COO

命令说明:查看文件的第2行到3行,使用地址范围“2,3”。取行就用sed,最简单

[root@chensiqi1 ~]# sed -n '1~2p' person.txt 
101,chensiqi,CEO
103,Alex,COO
105,feixue,CIO

命令说明:打印文件的1,3,5行。~代表步长

[root@chensiqi1 ~]# sed -n 'p' person.txt 
101,chensiqi,CEO
102,zhangyang,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO

命令说明:不指定地址范围,默认打印全部内容。

6.2.4.2 按字符串查询

[root@chensiqi1 ~]# sed -n '/CTO/p' person.txt 
102,zhangyang,CTO

命令说明:打印含CTO的行

[root@chensiqi1 ~]# sed -n '/CTO/,/CFO/p' person.txt 
102,zhangyang,CTO
103,Alex,COO
104,yy,CFO

命令说明:打印含CTO的行到含CFO的行。

6.2.4.3 混合查询

[root@chensiqi1 ~]# sed -n '2,/CFO/p' person.txt 
102,zhangyang,CTO
103,Alex,COO
104,yy,CFO

命令说明:打印第2行到含CFO的行。

[root@chensiqi1 ~]# sed -n '/feixue/,2p' person.txt 
105,feixue,CIO

命令说明:特殊情况,前两行没有匹配到feixue,就向后匹配,如果匹配到feixue就打印此行。所以这种混合地址不推荐使用。

6.2.4.4 过滤多个字符

[root@chensiqi1 ~]# sed -rn '/chensiqi|yy/p' person.txt 
101,chensiqi,CEO
104,yy,CFO

命令说明:
    使用扩展正则“|”,为了不使用转义符号“\”,因此使用-r选项开启扩展正则表达式模式

7.sed命令应用知识扩展

7.1 sed修改文件的同时进行备份

[root@chensiqi1 ~]# cat person.txt 
101,chensiqi,CEO
102,zhangyang,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO
[root@chensiqi1 ~]# sed -i.bak 's#zhangyang#NB#g' person.txt 
[root@chensiqi1 ~]# cat person.txt
101,chensiqi,CEO
102,NB,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO
[root@chensiqi1 ~]# cat person.txt.bak 
101,chensiqi,CEO
102,zhangyang,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO

命令行说明:
    在-i参数的后边加上.bak(.任意字符),sed会对文件进行先备份后修改

7.2 特殊符号=获取行号

[root@chensiqi1 ~]# sed '=' person.txt
1
101,chensiqi,CEO
2
102,NB,CTO
3
103,Alex,COO
4
104,yy,CFO
5
105,feixue,CIO

命令说明:使用特殊符号“=”就可以获取文件的行号,这是特殊用法,记住即可。从上面的命令结果我们也发现了一个不好的地方:行号和行不在一行。

[root@chensiqi1 ~]# sed '1,3=' person.txt
1
101,chensiqi,CEO
2
102,NB,CTO
3
103,Alex,COO
104,yy,CFO
105,feixue,CIO

命令说明:只打印1,2,3行的行号,同时打印输出文件中的内容

[root@chensiqi1 ~]# sed '/yy/=' person.txt
101,chensiqi,CEO
102,NB,CTO
103,Alex,COO
4
104,yy,CFO
105,feixue,CIO

命令说明:
    只打印正则匹配行的行号,同时输出文件中的内容

[root@chensiqi1 ~]# sed -n '/yy/=' person.txt
4

命令说明:只显示行号但不显示行的内容即取消默认输出。

[root@chensiqi1 ~]# sed -n '$=' person.txt
5

命令说明:
    “$”代表最后一行,因此显示最后一行的行号,变相得出文件的总行数。

方法改进:

[root@chensiqi1 ~]# sed '=' person.txt | sed 'N;s#\n# #'
1 101,chensiqi,CEO
2 102,NB,CTO
3 103,Alex,COO
4 104,yy,CFO
5 105,feixue,CIO

命令说明:前面sed获取文件的行号有一个缺点,我们这里使用Sed命令N来补偿这个缺点。Sed命令N读取下一行数据并附加到模式空间。

7.3 sed如何取不连续的行

[root@chensiqi1 ~]# sed -n '1p;3p;5p' person.txt
101,chensiqi,CEO
103,Alex,COO
105,feixue,CIO

7.4 特殊符号{}的使用

[root@chensiqi1 ~]# sed -n '2,4p;=' person.txt
1
102,NB,CTO
2
103,Alex,COO
3
104,yy,CFO
4
5

命令说明:-n去掉默认输出,2,4p,输出2到4行内容,=输出全部的行的行号

[root@chensiqi1 ~]# sed -n '2,4{p;=}' person.txt
102,NB,CTO
2
103,Alex,COO
3
104,yy,CFO
4

命令说明:
    ‘2,4{p;=}’代表统一输出2,4行的行号和内容

6.awk

awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。
awk有3个不同版本: awk、nawk和gawk,未作特别说明,一般指gawk,gawk是 AWK的 GNU版本

6.1语法格式

awk [options] ‘program’ file…
awk [-F|-f|-v] ‘BEGIN{} //{command1; command2} END{}’ file

选项说明

option[选项]描述
-F指明输入时用到的字段分隔符
-vvar=value 自定义变量
-f调用脚本
‘’引用代码块
BEGIN初始化代码块,在对每一行进行处理之前,初始化代码,主要是引用全局变量,设置FS分隔符
//匹配代码块,可以是字符串或正则表达式
{}命令代码块,包含一条或多条命令
;多条命令使用分号分隔
END结尾代码块,在对每一行进行处理之后再执行的代码块,主要是进行最终计算或输出结尾摘要信息
内置变量描述
RS既record separator输入记录分隔符,表示每个记录输入的时候的分隔符,既行与行之间如何分隔。
ORS输出的记录分隔符,默认为换行符,即处理结果也是一行一行输出到屏幕
NR既number of record 记录(行)号,表示当前正在处理的记录(行)的号码,多文件记录递增
FNR与NR类似,不过多文件记录不递增,每个文件都从1开始
FS既field separator,输入字段(列)分隔符
OFS输出字段分隔符, 默认是空格,可以改为制表符等
NF既number of fileds,表示一行中列(字段)的个数
\t制表符
\n换行符
1.算术操作符
x+y加法
x-y减法
x*y乘法
x/y除法
x^y乘方
x%y取模
-x转换为负数
+x转换为数值
2.比较操作符
==等于
!=不等于
>大于
>=大于等于
<小于
<=小于等于
3.模式匹配符
~左边是否和右边匹配包含,与==相比不是精确比较
!~是否不匹配
4.逻辑操作符
&&
||
!
function_name(argu1, argu2, …)函数调用
selector?if-true-expression:if-false-expression条件表达式(三目表达式)
特殊要点
-F’[:#/]’定义多个分隔符
$0表示整个当前行
$1每行第一个字段
$NF最后一列
$(NF-1)取倒数第二列内容
/pattern1/,/pattern2/ or /start pos/,NR==XXX or NR==XXX,NR==XXX范围模式,范围模式的时候,范围条件的时候,表达式必须能匹配一行
输出处理结果到文件
①在命令代码块中直接输出awk ‘NR!=1{print > “./fs”}’
②使用重定向进行输出awk ‘NR!=1{print}’ > ./fs
格式化输出描述
printf命令
printf “FORMAT” , item1, item2, … 不会自动换行,FORMAT中需要分别为后面每个item指定格式符。
%c显示字符的ASCII码
%d, %i显示十进制整数
%e, %E显示科学计数法数值
%f显示为浮点数
%g, %G以科学计数法或浮点形式显示数值
%s显示字符串
%u无符号整数
%%显示%自身
awk控制语句
1.{ statements;… } 组合语句
2.if(condition) {statements;…}
3.if(condition) {statements;…} else {statements;…}
4.while(conditon) {statments;…}
5.do {statements;…} while(condition)
6.for(expr1;expr2;expr3) {statements;…}
7.break
8.continue
9.delete array[index]
10.delete array
11.exit

数组

awk提供了数组来存放一组相关的值。
awk是一种编程语言,肯定也支持数组的运用,但是又不同于c语言的数组。数组在awk中被称为关联数组,因为它的下标既可以是数字也可以是字符串。下标通常被称作key,并且与对应的数组元素的值关联。数组元素的key和值都存储在awk程序内部的一张表中,通过一定散列算法来存储,所以数组元素都不是按顺序存储的。打印出来的顺序也肯定不是按照一定的顺序,但是我们可以通过管道来对所需的数据再次操作来达到自己的效果。

6.2示例

6.2.1统计文件大小

awk 'BEGIN{X=0} /^$/{ X+=1 } END{print "I find",X,"blank lines."}' test 
 ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is",sum}'                    //计算文件大小

6.2.2输出分隔符OFS

awk '$6 ~ /FIN/ || NR==1 {print NR,$4,$5,$6}' OFS="\t" netstat.txt
awk '$6 ~ /WAIT/ || NR==1 {print NR,$4,$5,$6}' OFS="\t" netstat.txt        
//输出字段6匹配WAIT的行,其中输出每行行号,字段4,5,6,并使用制表符分割字段

6.2.3格式化输出

netstat -anp|awk '{printf "%-8s %-8s %-10s\n",$1,$2,$3}' 
printf表示格式输出
%格式化输出分隔符
-8长度为8个字符
s表示字符串类型
打印每行前三个字段,指定第一个字段输出字符串类型(长度为8),第二个字段输出字符串类型(长度为8),
第三个字段输出字符串类型(长度为10)
netstat -anp|awk '$6=="LISTEN" || NR==1 {printf "%-10s %-10s %-10s \n",$1,$2,$3}'
netstat -anp|awk '$6=="LISTEN" || NR==1 {printf "%-3s %-10s %-10s %-10s \n",NR,$1,$2,$3}'

IF语句

awk -F: '{if($3>100) print "large"; else print "small"}' /etc/passwd
awk -F: 'BEGIN{A=0;B=0} {if($3>100) {A++; print "large"} else {B++; print "small"}} END{print A,"\t",B}' /etc/passwd                                                                                                                  //ID大于100,A加1,否则B加1
awk -F: '{if($3<100) next; else print}' /etc/passwd                         //小于100跳过,否则显示
awk -F: 'BEGIN{i=1} {if(i<NF) print NR,NF,i++ }' /etc/passwd   
awk -F: 'BEGIN{i=1} {if(i<NF) {print NR,NF} i++ }' /etc/passwd
另一种形式
awk -F: '{print ($3>100 ? "yes":"no")}'  /etc/passwd 
awk -F: '{print ($3>100 ? $3":\tyes":$3":\tno")}'  /etc/passwd

while语句

awk -F: 'BEGIN{i=1} {while(i<NF) print NF,$i,i++}' /etc/passwd 

数组

netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) print i,"\t",a[i]}'
netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) printf "%-20s %-10s %-5s \n", i,"\t",a[i]}'

应用1

awk -F: '{print NF}' helloworld.sh                                                       //输出文件每行有多少字段
awk -F: '{print $1,$2,$3,$4,$5}' helloworld.sh                                 //输出前5个字段
awk -F: '{print $1,$2,$3,$4,$5}' OFS='\t' helloworld.sh                 //输出前5个字段并使用制表符分隔输出
awk -F: '{print NR,$1,$2,$3,$4,$5}' OFS='\t' helloworld.sh           //制表符分隔输出前5个字段,并打印行号

应用2

awk -F'[:#]' '{print NF}'  helloworld.sh                                                  //指定多个分隔符: #,输出每行多少字段
awk -F'[:#]' '{print $1,$2,$3,$4,$5,$6,$7}' OFS='\t' helloworld.sh   //制表符分隔输出多字段

应用3
awk -F'[:#/]' '{print NF}' helloworld.sh //指定三个分隔符,并输出每行字段数 awk -F'[:#/]' '{print $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12}' helloworld.sh //制表符分隔输出多字段
应用4

计算/home目录下,普通文件的大小,使用KB作为单位
ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",sum/1024,"KB"}'
ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",int(sum/1024),"KB"}'         //int是取整的意思

应用5

统计netstat -anp 状态为LISTEN和CONNECT的连接数量分别是多少
netstat -anp|awk '$6~/LISTEN|CONNECTED/{sum[$6]++} END{for (i in sum) printf "%-10s %-6s %-3s \n", i," ",sum[i]}'

应用6

统计/home目录下不同用户的普通文件的总数是多少?

ls -l|awk 'NR!=1 && !/^d/{sum[$3]++} END{for (i in sum) printf "%-6s %-5s %-3s \n",i," ",sum[i]}'   
统计/home目录下不同用户的普通文件的大小总size是多少?
ls -l|awk 'NR!=1 && !/^d/{sum[$3]+=$5} END{for (i in sum) printf "%-6s %-5s %-3s %-2s \n",i," ",sum[i]/1024/1024,"MB"}'

应用7

输出成绩表

awk 'BEGIN{math=0;eng=0;com=0;printf "Lineno.   Name    No.    Math   English   Computer    Total\n";printf "------------------------------------------------------------\n"}{math+=$3; eng+=$4; com+=$5;printf "%-8s %-7s %-7s %-7s %-9s %-10s %-7s \n",NR,$1,$2,$3,$4,$5,$3+$4+$5} END{printf "------------------------------------------------------------\n";printf "%-24s %-7s %-9s %-20s \n","Total:",math,eng,com;printf "%-24s %-7s %-9s %-20s \n","Avg:",math/NR,eng/NR,com/NR}' test0

企业面试题11:统计域名访问次数

处理以下文件内容,将域名取出并根据域名进行计数排序处理:(百度和sohu面试题)
http://www.etiantian.org/index.html
http://www.etiantian.org/1.html
http://post.etiantian.org/index.html
http://mp3.etiantian.org/index.html
http://www.etiantian.org/3.html
http://post.etiantian.org/2.html
思路:
1)以斜线为菜刀取出第二列(域名)
2)创建一个数组
3)把第二列(域名)作为数组的下标
4)通过类似于i++的形式进行计数
5)统计后把结果输出

过程演示:
第一步:查看一下内容
[root@chensiqi ~]# awk -F "[/]+" '{print $2}' file 
www.etiantian.org
www.etiantian.org
post.etiantian.org
mp3.etiantian.org
www.etiantian.org
post.etiantian.org

命令说明:
这是我们需要计数的内容
第二步:计数
[root@chensiqi ~]# awk -F "[/]+" '{i++;print $2,i}' file 
www.etiantian.org 1
www.etiantian.org 2
post.etiantian.org 3
mp3.etiantian.org 4
www.etiantian.org 5
post.etiantian.org 6

命令说明:
i++:i最开始是空的,当awk读取一行,i自身+1
第三步:用数组替换i
[root@chensiqi ~]# awk -F "[/]+" '{h[$2]++;print $2,h["www.etiantian.org"]}' file 
www.etiantian.org 1
www.etiantian.org 2
post.etiantian.org 2
mp3.etiantian.org 2
www.etiantian.org 3
post.etiantian.org 3

命令说明:
1)将i替换成h[$2];相当于我创建了一个数组h[],然后用$2作为我的房间号。但是目前房间里是没有东西的。也就是说h[$2]=h["www.etiantian.org"] and h["post.etiantian.org"] and h["mp3.etiantian.org"] 但是具体房间里是没有东西的也就是空。
2)h[$2]++就等于i++:也就是说我开始给房间里加东西;当出现同样的东西,我就++
3)print h["www.etiantian.org"]:意思就是说我开始要输出了。我要输出的是房间号为“www.etiantian.org”里面的内容。这里面的内容最早是空的,随着awk读取每一行一旦出现房间号为“www.etiantian.org”的房间时,我就给房间里的内容进行++。
4)综上,输出的结果中,每次出现www.etiantian.org时,h["www.etiantian.org"]就会++。因此最后的输出数字是3
第四步:输出最终计数结果
[root@chensiqi ~]# awk -F "[/]+" '{h[$2]++}END{for(i in h)print i,h[i]}' file 
mp3.etiantian.org 1
post.etiantian.org 2
www.etiantian.org 3
[root@chensiqi ~]# 

命令说明:
我们最终需要输出的是去重复以后的统计结果,所以得在END模块里进行输出
for(i in h)遍历这个数组,i里存的都是房间号
print i,h[i]:输出每一个房间号及其房间里的内容(计数结果)

参考文档

https://www.cnblogs.com/chensiqiqi/p/6382080.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值