shell 的世界里有两个好兄弟:sed 和 gawk. 今天先讲其一 sed.
sed: stream editor. 在编辑器处理数据之前,根据事先提供的规则来编辑数据流。
sed 有点类似于 Kafka, 对数据进行一行一行的编辑,行云流水,没有半点拖沓。当然 kafka 更加强大,实时捕获数据,还能指定更复杂的处理逻辑,并且能够发送到任何地方保存起来。sed 能接受的源头是文本文件,最终的结果还只能是普通的文本文件,实现的是文本到文本的转换。
sed options script file
详细的文档见这里: https://www.gnu.org/software/sed/manual/sed.html
常用的 3 个可选参数列在这里:
sed -e 's/cat/dog/' logfile.txt
sed -f Wordchange.sed logfile.txt
sed -e 's/cat/dog' -i logfile.txt
-e : 指定命令表达式,s/cat/dog 用 dog 取代文本中的 cat ; -f : 如果有多行表达式,且频繁修改,用文件存储这些命令表达式则显得尤为高效,而 -f 代表的就是命令文件; -i: in-place 就地修改并保存。如果不指定 sed 将修改后的结果输出到标准输出也就是屏幕上
主要是围绕着 script 做文章,指定的命令可以完成目标文本的转换, 而 options 则更多是一些可选的动作,比如直接修改文本而不是保存,指定多命令的文件等等。
革命要胜利,路线不能歪。所以首先要攻克的便是 script 命令。这里有份指南,从简到深,细细铺开来讲。
• sed script overview: sed script overview
• sed commands list: sed commands summary
• The "s" Command: sed’s Swiss Army Knife
• Common Commands: Often used commands
• Other Commands: Less frequently used commands
• Programming Commands: Commands for sed gurus
• Extended Commands: Commands specific of GNU sed
• Multiple commands syntax: Extension for easier scripting
[line address]X[options]
多命令也好,单行命令也好,多行命令也好,命令文件也罢,命令的格式逃不过上面这公式。
line address 是文本的行数范围,比如指定文本的 30 到 50 行,'30,50'; X 是单字命令,够简单,但是不好记。随时备份一张 X 的列表在你的桌面上,或许能帮你随用随查; options 就是单字命令的可选参数
sed -e '/^foo/d' -e 's/hello/world/' input.txt > output.txt
echo 's/hello/world/' > script2.sed
sed -e '/^foo/d' -f script2.sed input.txt > output.txt
/^foo 比指定行数(每一行在文本文件中总有一个行号)要来的灵活,^foo代表的就是开头以foo的那些行; /d 标识命令是 delete, 即删除行的操作; -e, -f, 都可以多次引用,其作用就是为了指定多个命令
可选的命令太多了,所以还是挑几个常用的命令来讲讲
[root@centos00 _data]# echo 'this is a cat dog' | sed -e 's/cat/fat/'
this is a fat dog
[root@centos00 _data]#
s 这单字命令,一定要严格按照格式:
s/original word/replaced word/
来编写,否则出现会这种错误:
sed: -e expression #1, char 9: unterminated `s' command
{#;d;q;p;n}
q - quit 在当前行退出(当前处理的文件),不再处理更多往下的行
[root@centos00 _data]# seq 5
1
2
3
4
5
[root@centos00 _data]# seq 5 | sed 3q
1
2
3
[root@centos00 _data]#
seq 是 sequence 命令,产生一组序列值;
3q 是 sed 单字命令应用,3 代表第三行,而 q 就是退出
d - delete 是删除满足条件的行,可以指定行号也可以使用条件表达式
[root@centos00 _data]# seq 5 | sed 3d
1
2
4
5
[root@centos00 _data]#
p - print 打印当前行,必须与 sed -n 可选参数同时使用,才奏效
[root@centos00 _data]# seq 5 | sed 3p
1
2
3
3
4
5
[root@centos00 _data]# seq 5 | sed 3p -n
3
[root@centos00 _data]#
-n 作为 sed 的可选参数,没有在文档中找到其原意,我暂 YY 它是 no print 的意思。
n - Next line , 隔行处理。指定多少个 n, 就隔多少行处理一次编辑
[root@centos00 _data]# seq 5 | sed 'n;s/./new line/'
1
new line
3
new line
5
[root@centos00 _data]#
[root@centos00 _data]# seq 5 | sed 'n;n;s/./new line/'
1
2
new line
4
5
[root@centos00 _data]#
{#;d;q;p;n} - 命令组合符号{;}
刚才那一案例已经说明白了 'n;n;s/./new line/' , 使用“;”即可将多个命令同时作用于一行上,而如果要作用于满足条件的行,则必须加上“{}”:
[root@centos00 _data]# seq 5 | sed -n '2{s/./new line/;p}'
new line
[root@centos00 _data]#
看完这些例子,不禁令我想到一个问题,在单字命令表达式
[line address]X[options]
中,line address 可以是数字型的行号,也可以是满足条件的行号。而什么样的条件可以被放在[line address]表达式中呢?
好比,我需要打印偶数行,表达式该怎么写?
固然,用 n 命令可以解决这个问题,但我们考察的是[line address]的用法
# 使用单字命令:
[root@centos00 _data]# seq 8 | sed -n '{n;p}'
2
4
6
8
[root@centos00 _data]#
使用~可以实现打印隔行的功能:
[root@centos00 _data]# seq 8 | sed -n '0~2p'
2
4
6
8
而[line address]还可以使用正则表达式:
[root@centos00 _data]# seq 20 | sed -n '/[2]/p'
2
12
20
[root@centos00 _data]#
/regular express/ 是正确引用正则表达式的方法,这里仅仅是打印包含2字符的那些行。
在 IT 领域,仅看理论而不动手,“学而不练”则惘。就像笔者一样,在玩 Oracle 那段时间天天用着,还蛮熟练的,中途转 SQL Server 做了几年,回头再用 sed 却手生得紧。拳不离手,曲不离口,文不离码,一点没错。