linux实战(一)

linux实战(一)----日志的截取-----文本过滤器grep、文本流式编辑器sed、报表生成器awk的运用

2015年12月25日 16:28:50 张小凡vip 阅读数 5404更多

所属专栏: linux基础与shell编程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/q383965374/article/details/50394765

我们前面已经学习过 linux的性能查询(top),以及网络端口查询(netstat)命令等等。

怎么让我们查询到的信息按   我们需要的格式 显示生成。

就是我们本章 需要 学习练习的。

主要是grep,sed,awk3个命令的运用。

grep主要负责搜索

sed主要负责处理行

awk主要复杂处理列

我们在下一章的内容再来学习实例,如果用这几个命令来进行性能监控等。

grep

作用

grep命令可以指定文件中搜索特定的内容,并将含有这些内容的行标准输出。

grep全称是Global Regular Expression Print,表示全局正则表达式版本,它的使用权限是所有用户。

格式

grep [options]

[options]主要参数: -c:只输出匹配行的计数。 -I:不区分大小写(只适用于单字符)。 -h:查询多文件时不显示文件名。 -l:查询多文件时只输出包含匹配字符的文件名。 -n:显示匹配行及行号。 -s:不显示不存在或无匹配文本的错误信息。 -v:显示不包含匹配文本的所有行。

pattern正则表达式主要参数: \:忽略正则表达式中特殊字符的原有含义。 ^:匹配正则表达式的开始行。 $: 匹配正则表达式的结束行。 \:到匹配正则表达式的行结束。 [ ]:单个字符,如[A]即A符合要求。 [ - ]:范围,如[A-Z],即A、B、C一直到Z都符合要求。 。:所有的单个字符。 * :有字符,长度可以为0。

 ....      保存已匹配的字符

正则表达式是Linux/Unix系统中非常重要的概念。正则表达式(也称为“regex”或“regexp”)是一个可以描述一类字符串的模式(Pattern)。

如果一个字符串可以用某个正则表达式来描述,我们就说这个字符和该正则表达式匹配(Match)。

这和DOS中用户可以使用通配符“*”代表任意字符类似。

在Linux系统上,正则表达式通常被用来查找文本的模式,以及对文本执行“搜索-替换”操作和其它功能。

实例

$ ls -l | grep '^a'

通过管道过滤ls -l输出的内容,只显示以a开头的行。

$ grep 'test' d*

显示所有以d开头的文件中包含test的行。

$ grep 'test' aa bb cc

显示在aa,bb,cc文件中匹配test的行。

$ grep '[a-z]\{5\}' aa

显示aa文件中所有包含每个字符串有5个连续小写字符的字符串的行。

$ grep 'w\(es\)t.*\1' aa

如果west被匹配,则es就被存储到内存中,并标记为1,然后搜索任意个字符(.*),这些字符后面紧跟着另外一个\1 ,\1也就是es,因为前面把es存储到了内存并默认标记为1了,找到就显示该行。如果用egrep或grep -E,就不用"\"号进行转义,直接写成'w(es)t.*\1'就可以了。

sed

作用

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

格式

sed [options] 'command' file(s)   sed [options] -f scriptfile file(s)  

[options]主要参数

-n :使用安静(silent)模式。在一般 sed 的用法中,所有来自 STDIN 的数据一般都会被列出到终端上。但如果加上 -n 参数后,则只有经过sed 特殊处理的那一行(或者动作)才会被列出来。

-e :直接在命令列模式上进行 sed 的动作编辑; -f :直接将 sed 的动作写在一个文件内, -f filename 则可以运行 filename 内的 sed 动作; -r :sed 的动作支持的是延伸型正规表示法的语法。(默认是基础正规表示法语法) -i :直接修改读取的文件内容,而不是输出到终端。

'command'主要参数

a :新增, a 的后面可以接字串,而这些字串会在新的一行出现(目前的下一行)~ c :取代, c 的后面可以接字串,这些字串可以取代 n1,n2 之间的行! d :删除,因为是删除啊,所以 d 后面通常不接任何咚咚; i :插入, i 的后面可以接字串,而这些字串会在新的一行出现(目前的上一行); p :列印,亦即将某个选择的数据印出。通常 p 会与参数 sed -n 一起运行~ s :取代,可以直接进行取代的工作哩!通常这个 s 的动作可以搭配正规表示法!例如 1,20s/old/new/g 就是啦!

pattern正则表达式主要参数

 ^    行首定位符           

/^my/  匹配所有以my开头的行

 $ 行尾定位符

 /my$/  匹配所有以my结尾的行

 . 匹配除换行符以外的单个字符 

/m..y/  匹配包含字母m,后跟两个任意字符,再跟字母y的行

 * 匹配零个或多个前导字符

 /my*/  匹配包含字母m,后跟零个或多个y字母的行

 []   匹配指定字符组内的任一字符

/[Mm]y/  匹配包含My或my的行

 [^]  匹配不在指定字符组内的任一字符

/[^Mm]y/  匹配包含y,但y之前的那个字符不是M或m的行

 ....      保存已匹配的字符     

1,20s/youyouself/\1r/  标记元字符之间的模式,并将其保存为标签1,之后可以使用\1来引用它。最多可以定义9个标签,从左边开始编号,最左边的是第一个。此例中,对第1到第20行进行处理,you被保存为标签1,如果发现youself,则替换为your。

 &      保存查找串以便在替换串中引用

s/my/**&**/  符号&代表查找串。my将被替换为**my**

 \<      词首定位符      

 /\<my/  匹配包含以my开头的单词的行

 \>      词尾定位符      

/my\>/  匹配包含以my结尾的单词的行

 x\{m\} 连续m个x  

 /9\{5\}/ 匹配包含连续5个9的行

 x\{m,\}      至少m个x      

/9\{5,\}/  匹配包含至少连续5个9的行

 x\{m,n\}     至少m个,但不超过n个     

/9\{5,7\}/  匹配包含连续5到7个9的行

定址

定址用于决定对哪些行进行编辑。地址的形式可以是数字、正则表达式、或二者的结合。如果没有指定地址,sed将处理输入文件的所有行。  地址是一个数字,则表示行号;是“$"符号,则表示最后一行。

实例

删除d命令

$ sed '2d' example

删除example文件的第二行。

$ sed '2,$d' example

删除example文件的第二行到末尾所有行。

$ sed '$d' example

删除example文件的最后一行。

$ sed '/test/'d example

删除example文件所有包含test的行。

替换s命令

$ sed 's/test/mytest/g' example

在整行范围内把test替换为mytest。如果没有g标记,则只有每行第一个匹配的test被替换成mytest。

$ sed -n 's/^test/mytest/p' example

(-n)选项和p标志一起使用表示只打印那些发生替换的行。也就是说,如果某一行开头的test被替换成mytest,就打印它。

$ sed 's/^192.168.0.1/&localhost/' example

&;符号表示替换换字符串中被找到的部份。所有以192.168.0.1开头的行都会被替换成它自已加localhost,变成192.168.0.1localhost。

$ sed -n 's/\(love\)able/\1rs/p' example

love被标记为1,所有loveable会被替换成lovers,而且替换的行会被打印出来。

$ sed 's#10#100#g' example

不论什么字符,紧跟着s命令的都被认为是新的分隔符,所以,“#”在这里是分隔符,代替了默认的“/”分隔符。表示把所有10替换成100。

选定行的范围逗号

$ sed -n '/test/,/check/p' example

所有在模板test和check所确定的范围内的行都被打印。

$ sed -n '5,/^test/p' example

打印从第五行开始到第一个包含以test开始的行之间的所有行。

$ sed '/test/,/check/s/$/sed test/' example

对于模板test和west之间的行,每行的末尾用字符串sed test替换。

多点编辑e命令

$ sed -e '1,5d' -e 's/test/check/' example

(-e)选项允许在同一行里执行多条命令。如例子所示,第一条命令删除1至5行,第二条命令用check替换test。命令的执行顺序对结果有影响。如果两个命令都是替换命令,那么第一个替换命令将影响第二个替换命令的结果。

$ sed --expression='s/test/check/' --expression='/love/d' example

一个比-e更好的命令是--expression。它能给sed表达式赋值。

从文件读入r命令

$ sed '/test/r file' example

file里的内容被读进来,显示在与test匹配的行后面,如果匹配多行,则file的内容将显示在所有匹配行的下面。

写入文件w命令

$ sed -n '/test/w file' example

在example中所有包含test的行都被写入file里。

追加命令a命令

$ sed '/^test/a\\this is a test line'  example

在example文件中'this is a test line'被追加到以test开头的行后面,sed要求命令a后面有一个反斜杠。

插入i命令

$ sed '/test/i\\new line-------------------------'   example

如果test被匹配,则把反斜杠后面的文本插入到匹配行的前面。

下一个n命令

$ sed '/test/{ n; s/aa/bb/; }'  example

如果test被匹配,则移动到匹配行的下一行,替换这一行的aa,变为bb,并打印该行,然后继续。

变形y命令

$ sed '1,10y/abcde/ABCDE/' example

把1--10行内所有abcde转变为大写,注意,正则表达式元字符不能使用这个命令。

退出q命令

$ sed '10q' example

打印完第10行后,退出sed。

保持和获取h命令和G命令

$ sed -e '/test/h' -e '$G example

在sed处理文件的时候,每一行都被保存在一个叫模式空间的临时缓冲区中,除非行被删除或者输出被取消,否则所有被处理的行都将打印在屏幕上。接着模式空间被清空,并存入新的一行等待处理。在这个例子里,匹配test的行被找到后,将存入模式空间,h命令将其复制并存入一个称为保持缓存区的特殊缓冲区内。第二条语句的意思是,当到达最后一行后,G命令取出保持缓冲区的行,然后把它放回模式空间中,且追加到现在已经存在于模式空间中的行的末尾。在这个例子中就是追加到最后一行。简单来说,任何包含test的行都被复制并追加到该文件的末尾。

保持和互换h命令和x命令

$ sed -e '/test/h' -e '/check/x' example

互换模式空间和保持缓冲区的内容。也就是把包含test与check的行互换。

awk

作用

 awk 比较倾向于一行当中分成数个『栏位』(或者称为一个域,也就是一列)来处理。awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。

awk有3个不同版本: awk、nawk和gawk,未作特别说明,一般指gawk,gawk 是 AWK 的 GNU 版本。

awk其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母。实际上 AWK 的确拥有自己的语言: AWK 程序设计语言 , 三位创建者已将它正式定义为“样式扫描和处理语言”。它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其他的功能。

格式

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

commands

awk的命令非常多,因为它甚至可以算是一个编程语言。我们这里就不详细讲述了。后面的实例学习中会了解到一部分常用的命令。

这里大概给出awk中的一些学习目录如下:

print和printf

awk中同时提供了print和printf两种打印输出的函数。 其中print函数的参数可以是变量、数值或者字符串。字符串必须用双引号引用,参数用逗号分隔。如果没有逗号,参数就串联在一起而无法区分。这里,逗号的作用与输出文件的分隔符的作用是一样的,只是后者是空格而已。 printf函数,其用法和c语言中printf基本相似,可以格式化字符串,输出复杂时,printf更加好用,代码更易懂。

awk的环境变量

变量描述 $n 当前记录的第n个字段,字段间由FS分隔。 $0 完整的输入记录。 ARGC 命令行参数的数目。 ARGIND 命令行中当前文件的位置(从0开始算)。 ARGV 包含命令行参数的数组。 CONVFMT 数字转换格式(默认值为%.6g) ENVIRON 环境变量关联数组。 ERRNO 最后一个系统错误的描述。 FIELDWIDTHS 字段宽度列表(用空格键分隔)。 FILENAME 当前文件名。 FNR 同NR,但相对于当前文件。 FS 字段分隔符(默认是任何空格)。 IGNORECASE 如果为真,则进行忽略大小写的匹配。 NF 当前记录中的字段数。 NR 当前记录数。 OFMT 数字的输出格式(默认值是%.6g)。 OFS 输出字段分隔符(默认值是一个空格)。 ORS 输出记录分隔符(默认值是一个换行符)。 RLENGTH 由match函数所匹配的字符串的长度。 RS 记录分隔符(默认是一个换行符)。 RSTART 由match函数所匹配的字符串的第一个位置。 SUBSEP 数组下标分隔符(默认值是\034)。

awk运算符

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

专属正则表达式元字符

一般通用的元字符集就不讲了,可参考我的Sed和Grep。以下几个是gawk专用的,不适合unix版本的awk。 \Y 匹配一个单词开头或者末尾的空字符串。 \B 匹配单词内的空字符串。 \< 匹配一个单词的开头的空字符串,锚定开始。 \> 匹配一个单词的末尾的空字符串,锚定末尾。 \w

匹配一个字母数字组成的单词。 \W 匹配一个非字母数字组成的单词。 \‘ 匹配字符串开头的一个空字符串。 \' 匹配字符串末尾的一个空字符串。

awk编程

下面列举awk编程需要了解的东西:

变量 BEGIN模块 END模块 重定向和管道 条件语句 if语句 if/else语句,用于双重判断。 if/else else if语句,用于多重判断。 循环 数组 下标与关联数组 awk的内建函数 字符串函数 时间函数 日期和时间格式说明符 内建数学函数 自定义函数

实例

截取单列

last会列出最近登录的情况, 仅取出前五行

假设last -n 5的输出如下

[root@www ~]# last -n 5
root     pts/1   192.168.1.100  Tue Feb 10 11:21   still logged in
root     pts/1   192.168.1.100  Tue Feb 10 00:46 - 02:28  (01:41)
root     pts/1   192.168.1.100  Mon Feb  9 11:41 - 18:30  (06:48)
dmtsai   pts/1   192.168.1.100  Mon Feb  9 11:41 - 11:41  (00:00)
root     tty1                   Fri Sep  5 14:09 - 14:10  (00:01)

如果只是显示最近登录的5个帐号  也就是第一列

#last -n 5 | awk  '{print $1}'
root
root
root
dmtsai
root

awk工作流程是这样的:读入有'\n'换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域,$0则表示所有域,$1表示第一个域,$n表示第n个域。默认域分隔符是"空白键" 或 "[tab]键",所以$1表示登录用户,$3表示登录用户ip,以此类推。

设置分隔符

默认域分隔符是"空白键" 或 "[tab]键",如果想用其它符合作分隔符,参照下例:

/etc/passwd中是用:分割的

如下:

#cat /etc/passwd 
root:x:0:0:root:/root:/bin/bash 
daemon:x:2:2:daemon:/sbin:/sbin/nologin 
bin:x:1:1:bin:/bin:/sbin/nologin
sys:x:80:80:desktop:/var/lib/menu/kde:/sbin/nologin 

如果只是显示/etc/passwd的账户

#cat /etc/passwd |awk  -F ':'  '{print $1}'  
root
daemon
bin
sys

-F指定域分隔符为':'。     {print $1}输出第一列

显示多行

显示/etc/passwd的账户和账户对应的shell,显示时账户与shell之间以tab键分割

#cat /etc/passwd |awk  -F ':'  '{print $1"\t"$7}'
root    /bin/bash
daemon  /bin/sh
bin     /bin/sh
sys     /bin/sh

-F指定域分隔符为':'。     {print $1 "\t" $7} 输出第一列  tab  和 第7列

使用BEGIN END模块

显示/etc/passwd的账户和账户对应的shell,而账户与shell之间以逗号分割,而且在所有行添加列名name,shell,在最后一行添加"blue,/bin/nosh"。

#cat /etc/passwd |awk  -F ':'  'BEGIN {print "name,shell"}  {print $1","$7} END {print "blue,/bin/nosh"}'
name,shell
root,/bin/bash
daemon,/bin/sh
bin,/bin/sh
sys,/bin/sh
blue,/bin/nosh

awk工作流程是这样的:先执行BEGING,然后读取文件,读入有/n换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域,$0则表示所有域,$1表示第一个域,$n表示第n个域,随后开始执行模式所对应的动作action。接着开始读入第二条记录······直到所有的记录都读完,最后执行END操作。

正则搜索

搜索/etc/passwd里有root关键字的所有行

#awk -F ':'  '/root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash

这种是pattern的使用示例,匹配了pattern(这里是root)的行才会执行action(没有指定action,默认输出每行的内容)。 搜索支持正则,例如找root开头的: awk -F ':'  '/^root/' /etc/passwd

正则搜索显示单列

搜索/etc/passwd有root关键字的所有行,并显示对应的shell  也就是第7列

# awk -F ':'  '/root/{print $7}' /etc/passwd             
/bin/bash

这里指定了action{print $7}

awk环境变量的运用

我们上面提过都有哪些环境变量。 现在我们要统计/etc/passwd文件中的:文件名,每行的行号,每行的列数 使用到的变量参数如下: FILENAME           awk浏览的文件名 NR                 已读的记录数  也就是第几行 NF                 浏览记录的域的个数  也就是 共几列 $0 输出整行

#awk  -F ':'  '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:"$0}' /etc/passwd
filename:/etc/passwd,linenumber:1,columns:7,linecontent:root:x:0:0:root:/root:/bin/bash
filename:/etc/passwd,linenumber:2,columns:7,linecontent:daemon:x:1:1:daemon:/usr/sbin:/bin/sh
filename:/etc/passwd,linenumber:3,columns:7,linecontent:bin:x:2:2:bin:/bin:/bin/sh
filename:/etc/passwd,linenumber:4,columns:7,linecontent:sys:x:3:3:sys:/dev:/bin/sh

使用printf替代print

printf就是线使用占位符占位,后面再一起传入参数,可以让代码更加简洁,易读

awk  -F ':'  '{printf("filename:%s,linenumber:%s,columns:%s,linecontent:%s\n",FILENAME,NR,NF,$0)}' /etc/passwd

自定义变量

统计/etc/passwd的账户人数,每一行是一个账户,因为刚好awk是逐行遍历,所以我们自定义一个count自加就行。 当然 定义count为0需要在 awk逐行遍历之前  所以需要用BEGIN模块。

awk 'BEGIN {count=0;print "[start]user count is ", count} {count=count+1;print $0;} END{print "[end]user count is ", count}' /etc/passwd
[start]user count is  0
root:x:0:0:root:/root:/bin/bash
...
[end]user count is  40

运算

我们需要统计某个文件夹下的文件占用的字节数 因为文件占用的字节数 在 ls -l命令中的第5列 所以我们使用如下命令:

ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ", size}'
[end]size is  8657198

如果以M为单位显示:

ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ", size/1024/1024,"M"}' 
[end]size is  8.25889 M

注意,统计不包括文件夹的子目录。

条件语句

统计某个文件夹下不等于4096的其它文件占用的字节数-----过滤4096大小的文件:

ls -l |awk 'BEGIN {size=0;print "[start]size is ", size} {if($5!=4096){size=size+$5;}} END{print "[end]size is ", size/1024/1024,"M"}' 
[end]size is  8.22339 M

数组

显示/etc/passwd的账户

awk -F ':' 'BEGIN {count=0;} {name[count] = $1;count++;}; END{for (i = 0; i < NR; i++) print i, name[i]}' /etc/passwd
0 root
1 daemon
2 bin
3 sys
4 sync
5 games
......

awk编程的内容极多,这里只罗列简单常用的用法,更多请参考 http://www.gnu.org/software/gawk/manual/gawk.html

(adsbygoogle = window.adsbygoogle || []).push({});

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券