运维开发网

关于Linux中的awk、sed高级用法与案例,你想知道的都在这!

运维开发网 https://www.qedev.com 2021-04-18 14:40 出处:51CTO 作者:mb6072e237393be
awk    命令是一种编程语言,用于在linux/unix下对文本和数据进行处理。而且它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。sed 命令是利用脚本来处理文本文件。sed 可依照脚本的指令来处理、编辑文本文件。sed 主要用来自动编辑一个或多个文件、简化对文件的反复操作、编写转换程序等。在介绍awk和sed的用法之前先放入一些正则表达式,因为后

awk    命令是一种编程语言,用于在Linux/unix下对文本和数据进行处理。

而且它支持用户自定义函数和动态正则表达式等先进功能,是Linux/unix下的一个强大编程工具。


sed 命令是利用脚本来处理文本文件。

sed 可依照脚本的指令来处理、编辑文本文件。sed 主要用来自动编辑一个或多个文件、简化对文件的反复操作、编写转换程序等。


在介绍awk和sed的用法之前先放入一些正则表达式,因为后面会依靠正则表达式!

  • ^        行首定位符    ^abc

  • $        行尾定位符    abc$

  • .        匹配单个字符    .bc  a.c  a..

  • *        匹配前导符0到多次    ab*c

  • .*        任意多个字符

  • []        匹配指定范围内的1个字符        [aA]bc

  • [-]        匹配指定范围内的1个字符        [a-z]bc  [0-9]bc  [a-Z0-9]bc

  • [^]        匹配不在指定范围内的字符        [^a]bc  [^a-z0-9]bc

  • \        转义元字符    \.  \$  \1

  • \<        词首定位符    \<abc

  • \>        词尾定位符    abc\>

  • \(..\)        匹配稍后使用的字符的标签        :%s /10.0.0.10/10.0.0.20/

                        :%s /\(10.0.0.\)/\120/

                        :%s /\(10.\)\(0.\)\(0.\)10/\1\2\320/

                        :3,9s/\(.*\)/#\1/

  • x\{m\}        字符x重复出现m次            x\{2\}

  • x\{m,\}        字符x重复出现m次以上        x\{3,\}

  • x\{m,n\}    字符x重复出现m到n次        x\{3,5\

========扩展正则表达式

  • grep 过滤需要加\转义  如:x\{m\}

  • egrep支持扩展元字符不用加\转义符    如:x{m}

  • +        匹配一个或多个前导字符        abc+  [a-z]+bc

  • ?        匹配0个或1个前导字符        ab?c

  • a|b        a或b                abc|cba  

  • ()        组字符                love(abc|cba)ov+  ov+  (ov)+

  • (..)(..)\1\2    标签匹配符            (love)abc\1abc

  • x{m}        字符x重复m次            x{5}

  • x{m,}        字符x重复最少m次            x{5,}

  • x{m,n}        字符x重复最m次到n次        x{5,10}    

POSIX字符类:

表达式            功能                实例

[:alnum:]        字母与数字字符            [[:alnum:]]+

[:alpha:]        字母字符(包括大小写字母)    [[:alpha:]]{4}

[:blank:]        空格与制表符            [[:blank:]*

[:digit:]        数字字母                [[:digit:]]?

[:lower:]        小写字母                [[:lower:]]{5,}

[:upper:]        大写字母                [[:upper:]]+

[:punct:]        标点符号                [[:punct:]]

[:space:]        包括换行符回车等所有空白        [[:space:]]+


sed 流编辑器

sed的返回值只有在命令错误的情况下返回非0,命令正确后不管文件是否被修改都返回为0

命令        功能

a        在当前行后添加一行或多行

c        在新文本中修改(替换)当前行中的文本

d        删除行

i        在当前行之前插入文本

l        列出非打印字符

p        打印行

n        读入下一输入行,并从下一条命令而不是第一条命令开始对其的处理

q        结束或退出sed

!        对所选行以外的所有行应用命令

s        用一个字符串替换另一个

        s 替换标志

        g 在行内进行全局替换

        i 忽略大小写

r        从文件中读

w        将行写入文件

y        将字符转换为另一个字符(不支持正则表达式)

用法:

sed  -r  '//'  /etc/passwd

正则表达式要放在//中

sed -r          # -r表示支持扩展元字符

sed -ri          # -i表示真正的处理并改变文件

sed -rn          # -n表示静默输出,不会将文件中的内容输出到屏幕上

sed -rn 'p'      # 'p'表示sed每读取到一行到文件空间就会再输出一行

sed -ri  's/root/alice/' /etc/passwd  #将文件中的每一行中的root改为alice

sed -ri  's/root/alice/gi' /etc/passwd #将文件中的每一行中所有的root改为alice,并忽略大小写

sed -ri  's/root/alice/gi' /etc/passwd  也可以写为:sed -ri  's#root#alice#gi' /etc/passwd

sed -ri  '/root/g' /etc/passwd         #查找到root的行并删除

sed -ri  '/root/g' /etc/passwd  也可以写为 sed -ri  '\#root#g' /etc/passwd

sed -r 'd' /etc/passwd           #将删除文件中的所有内容

sed -r '3,5d' /etc/passwd         #删除3到5行

sed -r '/root/,5d' /etc/passwd      #找到包含root的行开始往下连续删除5行

sed -r '/root/,+5d' /etc/passwd      #找到包含root的行删除并往下再多删除5行

ed -r '/root/,!d' /etc/passwd        #不包含root的行都删除

sed -r '1~2d' /etc/passwd          #删除奇数行,从1行开始每隔2行删除一行

sed -r '0~2d' /etc/passwd          #删除偶数行,从0行开始每隔2行删除一行

sed -r '2N;s/\n//g' filename        #删除第二行中的换行符

sed -r ':aa;N;s/\n//;b aa ' filename    #全部查找换行符并删除

sed -r  '3d' /etc/passwd     #删除第三行

sed -r  '3{d;}' /etc/passwd     #删除第三行,  ;后面可以跟多个命令

vim中  3,5s/\(.*\)/#\1/            #表示将3到5行前面加上#

vim中  3,5s/.*/#&/            #表示将3到5行前面加上#

                    &表示查找之后匹配到的字符串

sed -r '3,5s/(.*)/#\1/'    /etc/passwd        #表示将3到5行前面加上#

sed -r '3,5s/.*/#&/'    /etc/passwd        #表示将3到5行前面加上#

sed -r '/root/s/(.*)/#\1/' /etc/passwd        #将所有包含root的行前面加上#

sed -r 's/(.)(.)(.*)/\1abc\2\3/' /etc/passwd    #将所有行中的第二个字母前加上abc

sed -r '/root/r /root/1.txt' /etc/passwd     #在包含root行的下一行读取/root/1.txt文件

sed -r '2iabc' /etc/passwd            #在第二行的上一行插入abc的新行

sed -r '2aabc' /etc/passwd             #在第二行的下一行插入abc的新行

sed -r '2cabc' /etc/passwd             #在第二行替换为abc的新行

sed -r '2c\abc\' /etc/passwd             #在第二行替换为abc的新行

sed -r '/adm/{n;d}'                #表示查找到adm后的下一行被删除

                        #n表示查找完后再再获取下一次命令

sed -r '/adm/{n;s/sbin/nobody/}'        #查找adm后再查找sbin替换为nobody(只替换一行)

暂存空间:    h H  g G

暂存空间中默认会有一个空行

h g :覆盖

H G :追加

h H :放入暂存空间

g G :从暂存空间取出

sed -r '1h;$G' /etc/passwd            #将第一行覆盖暂存,处理到最后一行时再将第一行追加到模式空间

sed -r '1{h;d};$G' /etc/passwd            #将第一行覆盖暂存后并删除,最后一行时将第一行追加到模式空间

sed -r '1h;2$g' /etc/passwd            #将第一行覆盖暂存,处理2到最后一行时覆盖到模式空间

sed -r '1h;2,3H;$G' /etc/passwd            #第一行覆盖暂存,2到3行追加,最后一行时再追加到模式空间

sed -r '/^[ \t]*#|^[ \t]*$/d' /etc/passwd    #删除注释以及空行

sed -r '/^[ \t]*(#|$)/d' /etc/passwd        #删除注释以及空行


awk用法

BEGIN{}            {}             END{}

行处理前        行处理        行处理后

BEGIN{} 通常同于定义一些变量,例如BEGIN{FS=":";OFS="---"}

$0:    awk变量$0保存当前记录的内容

NR:    显示行号(如果打开多个文件会当成一个文件显示行号)

FNR:    显示行号(如果打开多个文件会分别显示顺序行号)

NF:    保存记录的字段数,$1,$2,..$100,表示一共有多少个$

FS:    输入字段分隔符,默认空格

RS: 默认的输入记录分隔符,默认情况下是换行。

ORS: 输出记录分隔符,默认是换行。

awk -F":" '{print NR,$0}'       #打印文件所有内容并显示行号

awk -F'[ :\t]' '{print $1,$2}'    #支持多种字符一起分割,遇见其中一种就分割一次

awk 'BEGIN{FS=":"}{print $1}'    #定义分隔符为 ":"

awk 'BEGIN{FS=":";OFS="++"}/^root/{print $1,$2}'     # $1和$2之间输出的间隔是默认为空格,现在设定为之间以++形式输出,并查找到以root开头的行

awk -F":"'BEGIN{RS=" "}{print $0}'        #默认读取文件时,遇到换行符就代表一条记录结束,现在定义为遇到空格就是一条记录

awk 'BEGIN{ORS=" "}{print $0}'            #ORS默认将$0一条记录打印到屏幕时会进行回车,现在定义打印完时进行输出一个空格

printf

awk -F":" '{printf "%-15s %-10s %-15s\n",$1,$2,$3}' /etc/passwd

%s 字符类型

%d 数值类型

%f 浮点类型

15 占15字符

- 表示左对齐,默认是右对齐

printf默认不会在行尾自动换行,加\n表示一条记录后换行

awk -F":"'$1 ~/^root/' /etc/passwd    #输出$1中包含以root开头的记录

awk -F":"'$NF!~/bash$/' /etc/passwd     #输出不是以bash结尾的记录

awk -F":" '{if($3>300) {print $3} else{print $1}}' #if语句匹配

awk -F":" '$3 * 10 > 500' /etc/passwd  ### awk -F":" '{if($3*10>500){print $0}}'

awk -F":" '$1~/root/ && $3<=15'        #逻辑与

awk -F":" '$1~/root/ || $3<=15'        #逻辑或

awk -F":" '!($1~/root/ || $3<=15)'    #逻辑非    

awk -F":" '{if($3>0 && $3<1000){i++}} END{print i} #统计系统用户

【if...else语句】:

awk -F":"'{if($3==0){count++}else{i++}}END{

    print"管理员个数"count;print"普通用户个数"i}' /etc/passwd

【if...else if...else 语句】:

awk -F":"'{if($3==0){i++} else if($3>999){k++} else{j++}}END{

    print i;print k;print j}' /etc/passwd

awk -F":" '^root{i=1;while(i<=NF){print $i;i++}}'     #打印所有分割列

 =====【数组】

awk -F":"'{username[++i]=$1} END{print username[1]}' /etc/passwd

awk -F":"'{username[i++]=$1} END{print username[0]}' /etc/passwd

一些实战案例~

(统计/etc/passwd中各种类型shell的数量)

awk -F":" '{user[j++]=$1,} END{for (i in user){print i,user[i]}}' /passwd

#变量i是索引

(网站访问状态统计《当前实时状态》)

#netstat -anpt | grep ":80" |awk '{access_stat[$NF]++} END{

    for (i in access_stat){print i,access_stat[i]}}'

#ss -an | grep ":80" |awk '{access_stat[$NF]++} END{

    for (i in access_stat){print i,access_stat[i]}}'

(统计访问本主机的ip数量之次数)

#netstat -anpt |grep ":80" |awk -F":" '!/LISTEN/{ips[$(NF-1)]++} END{

    for (i in ips){print i,ips[i]}}' |sort -k2 -rn

(统计日志文件中的ip请求次数)

awk '/22\/Mar\/2017/{ips[$1]++} END{

for(i in ips){if(ips[i]>100){print i,ips[i]}}}' test.log |sort -k2 -rn

(统计用户名为4个字符的用户)

awk -F":"'$1~/^....$/{count++;print $1}END{

    print "count is: "count}' /etc/passwd

awk -F":"'length($1)==4{count++;print $1}END{

    print "count is: "count}' /etc/passwd

【awk中使用外部变量】

1. 在双引号的情况下使用

#var="bash"

#echo "unix script" |awk "gsub(/unix/,\"$bash\")"  

~~gsub()是一个函数,有sub和gsub两种,可以进行查找替换,gsub是全局性查找

2.在单引号的情况下使用

#var="bash"

#echo "unix script" |awk 'gsub(/unix/,"'"$var"'")'

#df -h |awk '{if(int($5)>10){print $6":"$5}}'

~~int()是一个函数,只取整数

#i=10

#df -h |awk '{if(int($5)>'''$i'''){print $6":"$5}}'

~~必须使用''' '''或"'" "'"才能使外部变量在awk中生效

awk参数 -v (建议使用)

#echo "unix script" |awk -v var="bash" 'gsub(/unix/,var)'

#awk -v user="root" -F":"'$1==user' /etc/passwd

 


【【Nginx 日志分析】】

日志格式:

这个日志输出格式是nginx.conf文件中定义的,是可以按照自己的项目进行修改的,一般情况都跟下面这个类似!

log_format main '$remote_addr - $remote_user [$time_local] "$request"'

                '$status $body_bytes_sent "$http_referer"'

                '"$http_user_agent" "$http_x_forwarded_for"';

                

                

日志文件中有以下一些条目,如:

114.242.15.54 - - [22/Mar/2017:09:42:08 +0800] "GET /css/20151103Style.css HTTP/1.1" 200 9041 "http://sz.cdn-my.mobiletrain.org/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36"

使用awk分割占的位置:

$remote_addr        $1

$time_local        $4

$request        $7

$status            $9

$body_bytes_sent    $10

(统计来访次数超过100次的ip):

#awk '/22\/Mar\/2017/ {ips[$1]++}END{for (i in ips){if(ips[i]>100){print i,ips[i]}}}' sz.org.log

#awk '/22\/Mar\/2017/ {ips[$1]++}END{for (i in ips){print i,ips[i]}}' sz.org.log |awk '$2>100'

(统计2017年9月5日,每个URL访问内容总大小($body_bytes_sent)):

#awk '/05\/Sep\/2017/{size[$7]+=$10}END{for (i in size){print i,size[i]}}' sz.org.log |sort -k2rn |head

(统计来访ip和访问时的状态码):

#awk '/05\/Sep\/2017/{ip_code[$1" "$9]++}END{for (i in ip_code){print i,ip_code[i]}}' sz.org.log |sort -k2rn |head

(统计来访ip和访问时的状态码404):

#awk '/05\/Sep\/2017/{if($9=="404"){ip_code[$1" "$9]++}}END{for(i in ip_code){print i,ip_code[i]}}' sz.org.log |sort -k2rn

(统计前一分钟的pv量):

#date=`date -d '-1 minute' +%d/+%b/%Y:%H:%M` ;awk -v date=$date '$0 ~ date {i++}END{print i}' sz.org.log

(统计8:30 - 9:00之间来访IP出现404的次数):

#awk '$4>="[05/Sep/2017:08:30:00" && $4<="[05/Sep/2017:09:00:00"{if($9=="404"){ip_code[$1" "$9]++}}END{for (i in ip_code){print i,ip_code[i]}}' sz.log

(统计某个时间段内所有状态码的次数):

#awk '/05\/Sep\/2017/{code[$9]++;total++}END{for (i in code){printf i"\t";printf code[i]"\t";printf "%.2f",code[i]/total*100;print "%"}}' sz.log

#awk '/05\/Sep\/2017/{code[$9]++;total++}END{for (i in code){printf i"\t";printf code[i]"\t";printf "%.2f%\n",code[i]/total*100}}' sz.log

~~输出结果为:

200        544        34.45%

-------------------------------------------------

(定期删除/date目录下修改时间大于7天的文件):    

#find /date -mtime +7 |xargs rm -rf       

(只保留最近2份的文件,其他的文件都删除):       

#ls -t /date/*.tar.gz |awk 'NR>2' |xargs rm -f    

-------------------------------------------------

0

精彩评论

暂无评论...
验证码 换一张
取 消