内容简介:对于我们后端人员来说,经常需要去服务器查找日志信息,排查详细错误信息或者监控服务器,强大如grep已经可以满足绝大部分需求,但是awk和sed这两个强大的命令工具也很好用,下面记录一下这两个工具如何使用。引自百科:AWK是一个优良的文本处理工具,Linux及Unix环境中现有的功能最强大的数据处理引擎之一。这种编程及数据操作语言(其名称得自于它的创始人阿尔佛雷德·艾侯、彼得·温伯格和布莱恩·柯林汉姓氏的首个字母)的最大功能取决于一个人所拥有的知识。awk经过改进生成的新的版本nawk,gawk,现在默认li
为什么要用
对于我们后端人员来说,经常需要去服务器查找日志信息,排查详细错误信息或者监控服务器,强大如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.
复制代码
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- composer更新命令及常用命令
- Linux命令行与命令
- 每天一个 Linux 命令(60): scp命令
- 每天一个 Linux 命令(59): rcp 命令
- 每天一个 Linux 命令(58): telnet 命令
- 每天一个 Linux 命令(56): netstat 命令
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Head First Rails
David Griffiths / O'Reilly Media / 2008-12-30 / USD 49.99
Figure its about time that you hop on the Ruby on Rails bandwagon? You've heard that it'll increase your productivity exponentially, and allow you to created full fledged web applications with minimal......一起来看看 《Head First Rails》 这本书的介绍吧!