前一篇我介绍了awk,这是一个全能的文本处理神器,因为它本身就是一门编程语言了,但对于很多场景,使用Linux预设的一些文本处理命令,会更方便快捷,如grep、sed等。
本篇就来介绍一下Linux上常用的文本处理命令,由于内容较多,分为上下两篇,这里是上篇。
主要包含cat、less、grep、head、tail,请看示例:
- # 用seq构造数据,tee的作用是写入文件的同时也将内容打印到屏幕上
- $ seq 5|tee data.txt
- 1
- 2
- 3
- 4
- 5
-
cat
- # cat可直接查看文件内容,加上-A选项可查看文件中不可见的特殊字符
- $ cat data.txt
- 1
- 2
- 3
- 4
- 5
-
less
- # less查看文件,其中-N表示显示行号,-S表示不换行显示
- # ctrl+f向前翻页,ctrl+b向后翻页,输入/再输入xxx搜索xxx,接着按n搜索下一个,N搜索上一下
- $ less -N -S data.txt
- # less常用来查看一页显示不了的情况,比如tree直接查看当前目录结构,可能会让你的屏幕刷一大堆文字(非常实用)
- $ tree | less -S
-
grep
- # grep可以使用正则表达式过滤文件内容,一般建议你加上-E,如果你想使用正则中的\d,建议你将-E换成-P
- $ grep -E '[345]' data.txt
- 3
- 4
- 5
- # 在当前目录递归的查找包含ERROR文件的行(非常实用)
- $ grep -rn 'ERROR' .
- # 输出查找到的行,以及其后面的2行,常用于查找异常栈(非常实用)
- $ cat data.txt|grep -A 2 '[2]'
- 2
- 3
- 4
- # 查找日志文件中最后产生的10条错误日志,-i用于忽略大小写,tac用于倒序输出行(非常实用)
- tac app.log|grep -i -m10 'ERROR'|tac
-
head与tail
- # 获取前两行
- $ cat data.txt|head -n2
- 1
- 2
- # 获取后两行
- $ cat data.txt|tail -n2
- 4
- 5
- # 获取第3行到第4行
- $ cat data.txt|tail -n +3|head -n2
- 3
- 4
- # -f会在文件写新行时,同步将其显示出来,常用于动态观察日志(非常实用)
- # 在less中,也可以按Shift + f实现类似效果
- $ tail -f app.log
-
tr
tr用于替换删除单个字符,如下:
- # 替换a为c
- $ echo aba|tr a c
- cbc
- # 替换为大写
- $ echo aba|tr [a-z] [A-Z]
- ABA
- # 删除换行
- $ seq 5|tr -d $'\n'
- 12345
-
cut
用于字符串分割,如下:
- $ echo 'a,b,c,d,e'|cut -d, -f2
- b
- $ echo 'a,b,c,d,e'|cut -d, -f2-4
- b,c,d
- $ echo 'a,b,c,d,e'|cut -d, -f2-
- b,c,d,e
- $ echo 'a,b,c,d,e'|cut -d, -f-2
- a,b
-
sed
用于替换修改文本,有流文本编辑器之称。
基本语法形如pattern action,sed会读取每一行,看是否匹配pattern,如果匹配则执行action。
如sed '3,5 s/a/c/g'将第3到5行中的a替换为c,其中3,5为pattern部分,s/a/c/g为action部分,只有满足pattern条件的行,action才会执行,pattern部分可以省略,这样每一行都会执行action。
- # yes可以用来不断的重复生成字符串,以此作为我们的测试数据
- $ yes abcde|head -n5
- abcde
- abcde
- abcde
- abcde
- abcde
- # 第3到5行中的a替换为c,其中的g表示所有的a,都替换为c
- $ yes abcde|head -n5|sed '3,5 s/a/c/g'
- abcde
- abcde
- cbcde
- cbcde
- cbcde
-
另外pattern action还可以是如下的形式:
- # 第3行到第5的a替换为c,第2行到第4行的b替换为d
- $ yes abcde|head -n5|sed '3,5 s/a/c/g; 2,4 s/b/d/g'
- abcde
- adcde
- cdcde
- cdcde
- cbcde
- # 第3到5行中,其中3到4行执行a替换为c,第4到5行执行b替换为d
- $ yes abcde|head -n5|sed '3,5{3,4 s/a/c/g; 4,5 s/b/d/g}'
- abcde
- abcde
- cbcde
- cdcde
- adcde
- # 非第3到5行的行,将a替换为c
- $ yes abcde|head -n5|sed '3,5! s/a/c/g'
- cbcde
- cbcde
- abcde
- abcde
- abcde
-
另外sed默认会打印执行action处理后的每一行,加上-n选项可以关掉默认打印,如下:
- # 显示1到3行,这里action为p,表示打印,-n用来关闭默认打印,不然1到3行会打印2遍,p一般都和-n配合使用
- $ seq 5|sed -n '1,3 p'
- 1
- 2
- 3
- # pattern部分可以使用正则表达式,注意sed中的正则也不能使用\d,且记得时常搭配-E选项
- # 注意pattern部分和action部分是可以随意组合的,也就是说正则形式的pattern也可以和s搭配使用
- $ seq 5|sed -n '/[2-4]/ p'
- 2
- 3
- 4
- # pattern部分也可以是逗号分隔的两个正则表达式,匹配从找到第一个正则表达式开始的行,到找到第二个正则表达式的行结束
- $ seq 5|sed -n '/[2]/,/[4]/ p'
- 2
- 3
- 4
- # 打印第1行,以及之后第间隔2行的行
- $ seq 5|sed -n '1~2 p'
- 1
- 3
- 5
-
除了s(替换)与p(打印)外,还有d(删除)、i(插入)、a(追加)、c(修改),如下:
- # 删除包含1和2的行
- $ seq 3|sed '/[1-2]/ d'
- 3
- # 向前插入一行,常用于设置csv标题
- $ seq 3|sed '1 i\id'
- id
- 1
- 2
- 3
- # 在最后一行之后追加一行
- $ seq 3|sed '$ a\id'
- 1
- 2
- 3
- id
- # 将第一行整行直接修改为id
- $ seq 3|sed '1 c\id'
- id
- 2
- 3
-
另外,s(替换)还有一些细节,这些细节实际上非常有用,体会一下:
- # 替换可以使用正则的捕获组功能
- $ echo 'id=1,name=zs'|sed -E 's/id=(\w+),name=(\w+)/\1 \2/'
- 1 zs
- # g表示将所有的a替换为c
- $ echo 'a,a,a,a'|sed 's/a/c/g'
- c,c,c,c
- # 3g表示将第3次匹配到的a以及后面匹配到的a,都替换为c
- $ echo 'a,a,a,a'|sed 's/a/c/3g'
- a,a,c,c
- # 没有g只能替换第1次匹配
- $ echo 'a,a,a,a'|sed 's/a/c/'
- c,a,a,a
- # 3表示只替换第3次匹配到的a为c
- $ echo 'a,a,a,a'|sed 's/a/c/3'
- a,a,c,a
-
Linux中sort、wc、uniq、comm可用于做一些简单的排序与分析任务,如下为示例文本数据:
- #用shell的here document语法,将data.txt中生成如下内容
- $ cat > data.txt <<eof
- > 2,zhangsan
- > 11,lisi
- > 3,wangwu
- > eof
-
- $ cat data.txt
- 2,zhangsan
- 11,lisi
- 3,wangwu
-
sort
- # -t用于指定字段分隔符,-k1表示使用第一个字段排序,sort默认使用空白字符作为字符分隔符,且默认升序排序
- $ cat data.txt |sort -t, -k1
- 11,lisi
- 2,zhangsan
- 3,wangwu
- # -n表示将字段值作为数字进行比较,不然就当成字符串比较,所以之前11排在2的前面
- $ cat data.txt |sort -t, -k1 -n
- 2,zhangsan
- 3,wangwu
- 11,lisi
- # -r表示倒序排序
- $ cat data.txt |sort -t, -k1 -n -r
- 11,lisi
- 3,wangwu
- 2,zhangsan
-
wc
- # 统计行数(常用)
- $ cat data.txt |wc -l
- 3
- # 统计行数其实sed也可以,=号表示输出当前行号
- $ cat data.txt |sed -n '$ ='
- 3
- # wc -c可用于获取中英混写情况下,在各字符编码下的占用字节数
- $ echo -n 'code日记'|iconv -t gbk|wc -c
- 8
- $ echo -n 'code日记'|iconv -t utf8|wc -c
- 10
-
uniq
uniq可以实现简单的分组计数,uniq处理的数据必须是已排好序的,所以一般使用uniq之前需要先sort一下,此命令非常实用。
- # 查看各状态socket的数量
- $ ss -nat|awk 'NR>1{print $1}'|sort|uniq -c
- 1 ESTAB
-
comm
comm用于对比两个文件中的行,求它们的差集与交集,输入的文件也需要先sort,此命令非常实用。
- # 第一列是comm第1部分相对第2部分的差集,第二列是comm第2部分相对第1部分的差集,第三列是交集
- $ comm <(seq 0 5) <(seq 1 6)
- 0
- 1
- 2
- 3
- 4
- 5
- 6
- # -1 -2表示不显示第一列与第二列,所以只显示了交集这一列
- $ comm -1 -2 <(seq 0 5) <(seq 1 6)
- 1
- 2
- 3
- 4
- 5
- # 当然-2 -3就可显示第一列的差集了
- $ comm -23 <(seq 0 5) <(seq 1 6)
- 0
-
这里需要两个示例文件,如下:
- $ cat person.txt
- 1,zhangsan
- 2,lisi
- 3,wangwu
-
- $ cat score.txt
- 1,92
- 2,78
- 3,93
-
paste
paste命令初一看以为是用来粘贴的,实际上并不是,它更像是做多文件的列式合并,如下:
- # 这看起来就像是两文件中相应行,合并到1行,用tab符分隔
- $ paste person.txt score.txt
- 1,zhangsan 1,92
- 2,lisi 2,78
- 3,wangwu 3,93
- # 这种列没对齐的数据,可以使用column -t使其对齐
- $ paste person.txt score.txt|column -t
- 1,zhangsan 1,92
- 2,lisi 2,78
- 3,wangwu 3,93
- # 指定:为合并分隔符
- $ paste person.txt score.txt -d ':'
- 1,zhangsan:1,92
- 2,lisi:2,78
- 3,wangwu:3,93
- # 体会一下-s选项(非常实用的选项)
- $ seq 5|paste -s -d,
- 1,2,3,4,5
- $ paste -sd, <(seq 1 5) <(seq 2 6)
- 1,2,3,4,5
- 2,3,4,5,6
- # 分组展示,-表示标准输入,非常实用
- $ seq 5|paste -d, - - -
- 1,2,3
- 4,5,
-
join
join命令可以实现类似SQL中join的效果,join命令使用的文件,也应该是事先排好序的,如下:
- # -1 1表示第一个文件使用第一个字段作为联接字段
- # -2 1表示第2个文件使用第一个字段作为联接字段
- # -t, 表示使用,作为字段分隔符
- $ join -1 1 -2 1 -t, -a1 person.txt score.txt
- 1,zhangsan,92
- 2,lisi,78
- 3,wangwu,93
-
Linux中的每个文本命令很多,每个看起来都不起眼,但它们组合起来可以做到很多事情。
且Linux中的grep、sed命令,当发现写的正则明明正确,执行却报错时,请加上-E选项,且不要使用\d,详细可搜索BRE、ERE、PCRE的区别。