sed,awk与grep
前言
关于标题:实际上,sed,awk和grep有一个共同的爹叫ed。sed和awk的区别是控制指令不太一样,而grep是起源于ed的一个指令:
g/re/p
,即全局-正则表达式匹配-打印,相当于把这个ed指令提取出来专门用于编辑。
之前学了Vim,不过Vim不太容易和其他命令行工具结合实现一些自动化任务。随后我将目光投向了sed和awk,它们二者都满足这个条件:可以将一个源的数据经过一些预定义的变换,输出到另一个源中。这其中,我对sed
相对更加熟悉一些,awk我感觉可能更复杂一些,而sed只需要正则表达式就行。比如我之前接触到的第一个sed表达式:
1 | sed -i 's@^\(deb.*stable main\)$@#\1\ndeb https://mirrors.tuna.tsinghua.edu.cn/termux/apt/termux-main stable main@' $PREFIX/etc/apt/sources.list |
上面那段是termux清华源的换源指令。单就命令格式上来看,我觉得和Vim的%s
替换表达式比较接近。
没接触之前,一直觉得这玩意很神奇;接触后更感觉这东西的设计太棒了,只需要指令,就能完成大段内容的编辑。
后来接触了正则和Vim之后觉得似曾相识,才发现sed的用法很像Vim的替换指令+正则。而且这一套下来,效率提升真不小。以前做一些爬虫都编辑麻烦,现在直接写个脚本就完事了。比如,我最近为了尝试这三个流编辑器,写了一个爬新闻的脚本:
1 |
|
这是一个简单的单行脚本:借助管道,将wget抓取到的网页直接交由grep,让它使用Perl正则表达式将新闻标题和链接匹配出来,再交由awk将具体的字段分离出来并按照markdown的标准进行加工,最后交由sed使用行编辑模式在每一行前面加上一个-
变换为markdown的列表。最后,将输出返回给echo -e
,得到加上标题的、完整的输出。
其实,上面的例子只用grep+sed/awk就行,但是为了表现三个编辑器各自的特点,还是安排它们共同完成了这个变换工作。希望这个例子能给你带来一个粗浅的印象。
那么,现在就开始正篇吧。
sed
首先说说sed它爹ed,这玩意是个很经典的行编辑器。不光可以交互编辑(类似于Vim,不过只能通过交互式指令输出操作结果,比如p输出当前行内容之类的),而且还能把操作指令存储下来
基本介绍
sed是一个流编辑器,它可以对文本文件或标准输入进行处理和编辑。sed的基本用法是:
1 | sed [options] 'script' file |
其中,options是一些可选的参数,script是一些sed命令,file是要处理的文本文件。下面是一些常用的options:
-n
:只打印匹配到的行,不打印所有行。-e
:可以指定多个script,按顺序执行。-f
:可以从一个文件中读取script。-i
:可以直接修改原文件,而不是输出到标准输出。-r
:可以使用扩展正则表达式。
sed的script由一些地址和命令组成,地址可以指定要处理的行,命令可以指定要执行的操作。下面是一些常用的地址和命令:
地址可以是一个数字,表示行号,如
3
表示第三行。地址可以是一个范围,表示行号之间的区间,如
3,5
表示第三行到第五行。地址可以是一个正则表达式,表示匹配该模式的行,如
/^abc/
表示以abc开头的行。地址可以是
$
,表示最后一行。如果不指定地址,默认对所有行进行处理。
命令可以是
a
,表示在当前行后面添加一些内容,如a\newline
表示在当前行后面添加一行newline。命令可以是
c
,表示用新的内容替换当前行,如c\newtext
表示用newtext替换当前行。命令可以是
d
,表示删除当前行,如d
表示删除当前行。命令可以是
p
,表示打印当前行,如p
表示打印当前行。命令可以是
s
,表示用新的内容替换匹配到的内容,如s/old/new/g
表示将old替换为new,g表示全局替换。
示例:
- 打印1-3行:
1 | sed -n '1,3p' file.txt |
- 删除1-3行:
1 | sed '1,3d' file.txt |
- 在所有行前加#:
1 | sed 's/^/#/g' file.txt |
- 将所有字母大写:
1 | sed 's/.*/\U&/g' file.txt |
参考资料
¹: Linux sed 命令 | 菜鸟教程
²: sed 命令快速入门 - 知乎
³: sed完全教程 - 知乎