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
2
3
#!/bin/bash

echo -e "# IT news Today\n\n$(wget -qO- https://www.ithome.com/block/rank.html | grep -oP '<li>\s*<a\K[^>]+' | awk -F '"' '{print "["$2"]("$6")"}' | sed 's/^/- /g')"

这是一个简单的单行脚本:借助管道,将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完全教程 - 知乎

awk

grep

作者

xeonds

发布于

2023-07-10

更新于

2024-05-13

许可协议

评论