AWK命令和SED命令

栏目: 服务器 · 发布时间: 4年前

内容简介:对于我们后端人员来说,经常需要去服务器查找日志信息,排查详细错误信息或者监控服务器,强大如grep已经可以满足绝大部分需求,但是awk和sed这两个强大的命令工具也很好用,下面记录一下这两个工具如何使用。引自百科:AWK是一个优良的文本处理工具,Linux及Unix环境中现有的功能最强大的数据处理引擎之一。这种编程及数据操作语言(其名称得自于它的创始人阿尔佛雷德·艾侯、彼得·温伯格和布莱恩·柯林汉姓氏的首个字母)的最大功能取决于一个人所拥有的知识。awk经过改进生成的新的版本nawk,gawk,现在默认li
AWK命令和SED命令
加班的日子也要抓紧时间学习哇

为什么要用

对于我们后端人员来说,经常需要去服务器查找日志信息,排查详细错误信息或者监控服务器,强大如grep已经可以满足绝大部分需求,但是awk和sed这两个强大的命令 工具 也很好用,下面记录一下这两个工具如何使用。

AWK

引自百科:

AWK是一个优良的文本处理工具,Linux及Unix环境中现有的功能最强大的数据处理引擎之一。这种编程及数据操作语言(其名称得自于它的创始人阿尔佛雷德·艾侯、彼得·温伯格和布莱恩·柯林汉姓氏的首个字母)的最大功能取决于一个人所拥有的知识。awk经过改进生成的新的版本nawk,gawk,现在默认 linux 系统下日常使用的是gawk,用命令可以查看正在应用的awk的来源(ls -l /bin/awk )

开始使用

先查询一份网络数据,使用重定向保存下来:

$ netstat -ano > netstat.txt
$ awk '{print}' netstat.txt
Proto Recv-Q Send-Q Local Address           Foreign Address         State       Timer
tcp        0      0 0.0.0.0:8009            0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 0.0.0.0:18090           0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 0.0.0.0:41999           0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 0.0.0.0:42801           0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 0.0.0.0:42869           0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 0.0.0.0:10050           0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 127.0.0.1:8005          0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0.0.0.0:10050        192.168.120.1:7569      TIME_WAIT   timewait (27.08/0/0)
复制代码

简单使用,输出第1列和第4列:

  • 其中单引号中的被大括号括起来的就是awk的语句,注意,其只能被单引号包含。
  • 其中的 n表示第几列。($0表示整个行)
$ awk '{print $1,  $4}' netstat.txt
Proto Local
tcp 0.0.0.0:8009
tcp 0.0.0.0:18090
tcp 0.0.0.0:41999
tcp 0.0.0.0:8080
tcp 0.0.0.0:42801
tcp 0.0.0.0:42869
tcp 0.0.0.0:22
tcp 0.0.0.0:10050
tcp 127.0.0.1:8005
复制代码

awk可以格式化输出,用过C和 Java 等语系的应该都挺熟悉:

$ awk '{printf "%-8s %-8s %-8s %-18s %-22s %-15s\n",$1,$2,$3,$4,$5,$6}' netstat.txt
Proto    Recv-Q   Send-Q   Local              Address                Foreign
tcp      0        0        0.0.0.0:8009       0.0.0.0:*              LISTEN
tcp      0        0        0.0.0.0:18090      0.0.0.0:*              LISTEN
tcp      0        0        0.0.0.0:41999      0.0.0.0:*              LISTEN
tcp      0        0        0.0.0.0:8080       0.0.0.0:*              LISTEN
复制代码

过滤记录

可以对其中某个或某些字段进行判断,使用比较判断符即可(通过与或非进行连接)

比较判断符:==、!=、>=、>=、>、< 连接符:|| 、&&、 !

例如筛选出第三列大于0的数据行:

$ awk '$3 > 0 {print }' netstat.txt
Proto Recv-Q Send-Q Local Address           Foreign Address         State       Timer
tcp        0     48 10.96.0.33:22           0.0.0.0:42280       ESTABLISHED on (0.20/0/0)
复制代码

如果需要打印行号的话,可以使用内建变量NR:

$ awk '$3 > 0 {print NR, $0 }' netstat.txt
1 Proto Recv-Q Send-Q Local Address           Foreign Address         State       Timer
23 tcp        0         0.0.0.0:22            0.0.0.0:42280     ESTABLISHED on (0.20/0/0)
复制代码

内建变量

内建变量相当于该程序的内置变量,可以直接拿来使用:

变量 变量含义
$0 当前记录(这个变量存放当前行的内容
n 当前记录的第n个字段,字段由分隔符FS分割
FS 输入字段分隔符,默认是空格或Tab
NF 当前记录中的字段个数,就是有多少列
NR 已经读出的记录数,就是行号,从1开始,如果有多个文件的话,这个值也是不断累加中
FNR 当前记录数,与NR不同的是,这个值是各自文件自己的行号
RS 输入的记录分隔符,默认是换行符
OFS 输出字段分隔符,默认也是空格
ORS 输出的记录分隔符,默认是换行符
FILENAME 当前输入文件的名字

例如有些文件的分隔符不是空格,而是其他,可以自定义分隔符:

$ awk 'BEGIN{FS=":"} {print $1, $3, $6}' /etc/passwd
nobody -2 /var/empty
root 0 /var/root
复制代码

上面命令等价于:(-F的意思就是制定分隔符)

$ awk -F: '{print $1, $3, $6}' /etc/passwd
复制代码

注意:如果要制定多个分隔符,可以使用:

awk -F '[;:]'

自定义输出字段的分隔符(例如制表符\t):

$ awk 'BEGIN{FS=":"} {print $1, $3, $6}' OFS="\t" /etc/passwd
nobody	-2	/var/empty
root	0	/var/root
daemon	1	/var/root
复制代码

字符串匹配

可以跟grep一样,匹配相关字符:

$ awk '/LISTEN|WAIT/' netstat.txt
tcp        0      0 0.0.0.0:8009            0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 0.0.0.0:18090           0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 0.0.0.0:41999           0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 0.0.0.0:42801           0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 0.0.0.0:42869           0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 0.0.0.0:10050           0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 127.0.0.1:8005          0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 0.0.0.0:10050           0.0.0.0:7569      TIME_WAIT   timewait (27.08/0/0)
复制代码

还可以精确匹配某个字段:

$ awk '$6 ~/LISTEN|CLOSE/ {print $0}' netstat.txt
tcp        0      0 0.0.0.0:8009            0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 0.0.0.0:18090           0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 0.0.0.0:41999           0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 0.0.0.0:42801           0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 0.0.0.0:42869           0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 0.0.0.0:10050           0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 127.0.0.1:8005          0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        1      0 0.0.0.0:44690           0.0.0.0:80            CLOSE_WAIT  off (0.00/0/0)
tcp6       0      0 :::27777                :::*                    LISTEN      off (0.00/0/0)
tcp6       0      0 :::10050                :::*                    LISTEN      off (0.00/0/0)
复制代码

其中:~表示模式开始,两个/中间是模式,相当于进行正则表达式的匹配(同样道理,在正则表达式前使用!可以进行取反操作,这里就不展示了)

拆分文件

指定某列为分类符,使用重定向就可以导出到不同的文件中,例如下列语句通过第六列进行分割:

$ awk 'NR!=1 {print > $6}' netstat.txt
$ ls
ESTABLISHED          TIME_WAIT            netstat.txt          test.txt     CLOSE_WAIT           LISTEN               off
复制代码

可以查看各自文件,发现已经是分类后的结果:

$ cat ESTABLISHED
tcp        0      0 0.0.0.0:38440        0.0.0.0:20880       ESTABLISHED keepalive (5806.94/0/0)
tcp        0      0 0.0.0.0:58814        0.0.0.0:20880        ESTABLISHED keepalive (5872.47/0/0)
tcp        0      0 0.0.0.0:49998        0.0.0.0:80        ESTABLISHED off (0.00/0/0)
tcp        0      0.0.0.03:22            0.0.0.02:42280    ESTABLISHED on (0.20/0/0)
tcp        0      0 0.0.0.0:56146        0.0.0.0:20892    ESTABLISHED keepalive (2661.21/0/0)
复制代码

同样,可以指定某些列进行输出,也可以使用复杂的表达式(例如if-else-if语句,awk是个脚本解释器)

$ awk 'NR!=1{if($6 ~ /TIME|ESTABLISHED/) print > "1.txt";
else if($6 ~ /LISTEN/) print > "2.txt";
else print > "3.txt" }' netstat.txt
$ ls *.txt
1.txt       2.txt       3.txt       netstat.txt
复制代码

注意,if-else语句要在同一个花括号{}里~

统计

下面语句是用来统计以.txt为后缀的文件总大小:

$ ll *.txt | awk '{sum+=$5} END {print sum}'
769.9
复制代码

同样,可以在统计时使用数据,分开统计不同项目的总数

用来统计网络状态

$ awk 'NR!=1{a[$6]+=1} END {for (i in a) print i ", " a[i];}' netstat.txt
LISTEN, 11
CLOSE_WAIT, 1
TIME_WAIT, 26
off, 7
ESTABLISHED, 10
复制代码

用来统计每个用户的进程占了多少内存:(通过ps -aux查看,第六列表示占用的内存)

$ ps -aux | awk 'NR!=1{a[$1]+=$6} END {for (i in a) print i ", " a[i]"kb";}'
apache, 156952kb
dbus, 1236kb
polkitd, 8252kb
named, 104220kb
libstor+, 148kb
mysql, 106304kb
root, 325464kb
复制代码

awk脚本

有两个关键字需要注意BEGIN和END:

  • BEGIN{这里放的是,执行前的语句}
  • END{这里放的是,执行后的语句}
  • {这里放的是处理每一行时要执行的语句}

例如下面例子,简单统计行数:(只是简单介绍一下脚本如何写,更多定制化的可以小伙伴去探索~)

$ vim cal.awk
#! /bin/awk -f
# 运行前
BEGIN {
    lineNumber = 0
    print "开始执行"
}
# 运行中
{
    lineNumber += 1
    printf "当前行号 %s, 数据为 %s \n", lineNumber, $0

}
# 运行后
END {
    print "结束"
}
复制代码

执行脚本(也可以使用./cal.awk netstat.txt)

$ awk -f cal.awk netstat.txt
awk -f cal.awk netstat.txt
开始执行
当前行号 1, 数据为 Proto Recv-Q Send-Q Local Address           Foreign Address         State       Timer
当前行号 2, 数据为 tcp        0      0 0.0.0.0:8009            0.0.0.0:*               LISTEN      off (0.00/0/0)
当前行号 3, 数据为 tcp        0      0 0.0.0.0:18090           0.0.0.0:*               LISTEN      off (0.00/0/0)
当前行号 4, 数据为 tcp        0      0 0.0.0.0:41999           0.0.0.0:*               LISTEN      off (0.00/0/0)
当前行号 5, 数据为 tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      off (0.00/0/0)
当前行号 6, 数据为 tcp        0      0 0.0.0.0:42801           0.0.0.0:*               LISTEN      off (0.00/0/0)
当前行号 7, 数据为 tcp        0      0 0.0.0.0:42869           0.0.0.0:*               LISTEN      off (0.00/0/0)
结束
复制代码

结合环境变量

通过使用-v参数和ENVIRON,与环境变量打交道:

$ echo $x
0
$ echo ${test}
LISTEN
$ awk -v val=${x} '$2==val || $6==ENVIRON["test"] { print $1, $2, $3}' netstat.txt
tcp 0 0
tcp 0 0
tcp 0 0
tcp 0 0
tcp 0 0
复制代码

当然,在使用环境变量的时候,记得要export该变量

SED命令

全称是:Stream EDitor,功能月awk类似,差别在于,sed比awk简单一点,常用于字符替换。匹配符可以使用正则表达式进行匹配,所以想要用更强大的功能,需要去了解一下正则表达式~

使用S命令替换

使用以下文本进行测试

$ cat self.txt
First line
    My name is John
Second line
    I like milk
Third line
    I like basketball
Four line
    I live in china
复制代码

S命令介绍:

s表示替换命令,/I/表示匹配I, /John/表示将前面的I替换成Json,/g表示进行所有行上所有字符的匹配(注意,匹配时区分大小写)

$ sed "s/I/John/g" self.txt
First line
    My name is John
Second line
    John like milk
Third line
    John like basketball
Four line
    John live in china
复制代码

这样只是对于输出流的字符进行替换,原文本的数据不会改变,有两种方法可以修改输出流的数据:

  • 使用重定向 >
$ sed "s/I/John/g" self.txt > other.txt
复制代码
  • 使用-i参数
$ sed -i "s/I/John/g" self.txt
复制代码

可以在每一行最前面加数据:(例如将文本开头加个#字符)

$ sed "s/^/#/g" self.txt
sed "s/^/#/g" self.txt
#First line
#    My name is John
#Second line
#    I like milk
#Third line
#    I like basketball
#Four line
#    I live in china
复制代码

可以在行末尾加一些数据:(例如加分割符或者结束符)

$ sed "s/$/---/g" self.txt
First line---
    My name is John---
Second line---
    I like milk---
Third line---
    I like basketball---
Four line---
    I live in china---
复制代码

使用正则表达式去掉html中的tags:

Html文本为:

<b>This is</b><p> a test file</p><span style="text-decoration: underline;"> @John hahah</span>
复制代码

替换脚本:

# 熟悉正则表达式的小伙伴应该不陌生
# 使用[^>]表示除了>之外的字符,*号表示任意个字符
$ sed "s/<[^>]*>//g" html.txt
This is a test file @John hahah
复制代码

可以指定替换特定行号的文本,多行间使用逗号(,)进行连接:(例如下面只替换第5到第8行的数据)

$ sed "5,8s/I/John/g" self.txt
First line
    My name is John
Second line
    I like milk             #这行的I没有被替换
Third line
    John like basketball     #替换了
Four line
    John live in china       #替换了
复制代码

测试文本:

$ cat 1.txt
This is first line.
This is second line.
This is third line.
This is four line.
复制代码

指定只替换每一行第一个出现的字符:

$ sed "s/s/S/1" 1.txt
ThiS is first line.
ThiS is second line.
ThiS is third line.
ThiS is four line.
复制代码

指定替换每一行第二个及第二个之后的字符:

$ sed "s/s/S/2g" 1.txt
This iS firSt line.
This iS Second line.
This iS third line.
This iS four line.
复制代码

多个匹配

如果需要在一次命令中,匹配多个模式,可以写多个匹配表达式,通过分号;进行分割:(例如下面将1,2行的This替换成That,3到最后一行的is替换成are)

$ sed '1,2s/This/That/g; 3,$s/is/are/g' 1.txt
That is first line.
That is second line.
Thare are third line.   #没想到将This的is也替换成are了=-=
Thare are four line.    #可以修改sed '1,2s/This/That/g; 3,$s/is/are/2' 1.txt, 指定替换第二个字符is
复制代码

可以使用&,用来当做被匹配的变量,然后在匹配的变量前后加一些内容:

$ sed 's/line/front [&] end/g' 1.txt
This is first front [line] end.
This is second front [line] end.
This is third front [line] end.
This is four front [line] end.
复制代码

圆括号匹配

圆括号括起来的正则表达式所匹配的字符串可以当成变量来使用,其中,\1表示第一个匹配,\2表示第二个匹配,以此类推)

$sed 's/^This is \([A-Za-z]*\) line.$/\1/g' 1.txt
first
second
third
four
复制代码

正则表达式博大精深,每次都是学到用时方恨少!

N命令

这条命令会将下一行的内容送入缓存区,两行并成一行进行匹配: (例如下面的命令,两行合成一行后,两行之间的换行符\n被替换成空格,所以输出结果,原偶数行与奇数行合并)

$ sed 'N;s/\n/ /g' self.txt
First line     My name is John
Second line     I like milk
Third line     I like basketball
Four line     I live in china
复制代码

a命令和i命令

a:表示append,在某行后面进行追加:

$ sed '$ a --- the end ---' 1.txt
This is first line.
This is second line.
This is third line.
This is four line.
--- the end ---
复制代码

i:表示insert,在某行之前进行插入:

$ sed '1 i --- the start ---' 1.txt
--- the start ---
This is first line.
This is second line.
This is third line.
This is four line.
复制代码

可以进行匹配,然后在匹配行后面进行追加或者之前插入数据:

$ sed '/line/a  I find a line' 1.txt
This is first line.
I find a line
This is second line.
I find a line
This is third line.
I find a line
This is four line.
I find a line
复制代码

c命令

C命令:替换命令,将匹配到的行替换掉

单行替换:

$ sed '2 c You have been replaced' 1.txt
This is first line.
You have been replaced
This is third line.
This is four line.
复制代码

多行替换

$ sed '2,$ c You have been replaced' 1.txt
This is first line.
You have been replaced
复制代码

或者匹配行进行替换:

$ sed '/This is/c You have been replaced' 1.txt
You have been replaced
You have been replaced
You have been replaced
You have been replaced
复制代码

d命令

d命令:delete,删除 跟上面的替换c命令很类似

单行删除:

$ sed '2 d' 1.txt
This is first line.
This is third line.
This is four line.
复制代码

多行替换

$ sed '2,$ d' 1.txt
This is first line.
复制代码

或者匹配行进行替换:

$ sed '/This is/d' 1.txt
# 都木有了=-=
复制代码

p命令

p命令:print,打印命令,与grep类似

# 匹配到third这一行,但是重复输出了
$ sed '/third/p' 1.txt
This is first line.
This is second line.
This is third line.
This is third line.
This is four line.
# 使用n参数进行过滤
$ sed -n '/third/p' 1.txt
This is third line.
# 多个模式匹配(两个模式中间的行次也会被匹配出来)
$ sed -n '/first/, /third/p' 1.txt
This is first line.
This is second line.
This is third line.
# 指定某一行到匹配行进行打印
$ sed -n '2,/four/p' 1.txt
This is second line.
This is third line.
This is four line.
复制代码

命令打包

多个命令可以使用分号进行分开,使用大括号括起来作为嵌套命令:

# 从一二行中,匹配到This字符,然后整行进行删除
$ sed '1,2 {/This/d}' 1.txt
This is third line.
This is four line.
# 从一二行中,匹配到This字符,然后再匹配first字符,最后整行进行删除
$ sed '1,2 {/This/{/first/d}}' 1.txt
This is second line.
This is third line.
This is four line.
# 多命令用分号;分开
# 例如删掉包含first的行次,并且给每一行的开头加上#号
$ sed '1,$ {/first/d;s/^/#/g}' 1.txt
#This is second line.
#This is third line.
#This is four line.
复制代码

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

JavaScript and Ajax for the Web, Sixth Edition

JavaScript and Ajax for the Web, Sixth Edition

Tom Negrino、Dori Smith / Peachpit Press / August 28, 2006 / $24.99

Book Description Need to learn JavaScript fast? This best-selling reference’s visual format and step-by-step, task-based instructions will have you up and running with JavaScript in no time. In thi......一起来看看 《JavaScript and Ajax for the Web, Sixth Edition》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具