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-regexp | PATTERN is an extended regular expression (ERE) |
-F, --fixed-strings | PATTERN is a set of newline-separated fixed strings |
-G, --basic-regexp | PATTERN is a basic regular expression (BRE) |
-P, --perl-regexp | PATTERN is a Perl regular expression |
-e, --regexp=PATTERN | use PATTERN for matching |
-f, --file=FILE | obtain PATTERN from FILE |
-i, --ignore-case | ignore case distinctions |
-w, --word-regexp | force PATTERN to match only whole words |
-x, --line-regexp | force PATTERN to match only whole lines |
-z, --null-data | a data line ends in 0 byte, not newline |
Miscellaneous | 描述 |
---|---|
-s, --no-messages | suppress error messages(预制错误信息) |
-v, --invert-match | select non-matching lines(选择非匹配行) |
-V, --version | display version information and exit |
–help | display this help text and exit |
Output control | 描述 |
---|---|
-m, --max-count=NUM | stop after NUM matches |
-b, --byte-offset | print the byte offset with output lines |
-n, --line-number | print line number with output lines |
–line-buffered | flush output on every line |
-H, --with-filename | print the file name for each match |
-h, --no-filename | suppress the file name prefix on output |
–label=LABEL | use LABEL as the standard input file name prefix |
-o, --only-matching | show only the part of a line matching PATTERN |
-q, --quiet, --silent | suppress all normal output |
–binary-files=TYPE | assume that binary files are TYPE;TYPE is ‘binary’, ‘text’, or ‘without-match’ |
-a, --text | equivalent to --binary-files=text |
-I | equivalent to --binary-files=without-match |
-d, --directories=ACTION | how to handle directories; |
ACTION is ‘read’, ‘recurse’, or ‘skip’ | |
-D, --devices=ACTION | how to handle devices, FIFOs and sockets;ACTION is ‘read’ or ‘skip’ |
-r, --recursive | like --directories=recurse |
-R, --dereference-recursiv | likewise, but follow all symlinks |
–include=FILE_PATTERN | search only files that match FILE_PATTERN |
–exclude=FILE_PATTERN | skip files and directories matching FILE_PATTERN |
–exclude-from=FILE | skip files matching any file pattern from FILE |
–exclude-dir=PATTERN | directories that match PATTERN will be skipped. |
-L, --files-without-match | print only names of FILEs containing no match |
-l, --files-with-matches | print only names of FILEs containing matches |
-c, --count | print only a count of matching lines per FILE |
-T, --initial-tab | make tabs line up (if needed) |
-Z, --null | print 0 byte after FILE name |
Context control | 描述 |
---|---|
-B, --before-context=NUM | print NUM lines of leading context(打印以文本起始的NUM行) |
-A, --after-context=NUM | print NUM lines of trailing context(打印以文本结尾的NUM行) |
-C, --context=NUM | print NUM lines of output context |
-NUM | same as --context=NUM(打印输出文本NUM行) |
–group-separator=SEP | use SEP as a group separator |
–no-group-separator | use empty string as a group separator |
–color[=WHEN], | |
–colour[=WHEN] | use markers to highlight the matching strings;WHEN is ‘always’, ‘never’, or ‘auto’ |
-U, --binary | do not strip CR characters at EOL (MSDOS/Windows) |
-u, --unix-byte-offsets | report 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 | 指明输入时用到的字段分隔符 |
-v | var=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]:输出每一个房间号及其房间里的内容(计数结果)