写在前面:
译者之前只使用过 grep,最近才了解到还有 sed 和 awk 这两个更高级的工具。所以特意 Google 了一下,找到了 Difference Between grep, sed, and awk 这篇文章,感觉还不错,简单易懂。所以尝试翻译一下,留作后续查找翻阅,第一次尝试做文章翻译,轻拍。
正文:
-
概览
在本文中,我们将介绍命令行工具 grep,sed 和 awk。 特别是,我们将研究它们之间的功能差异。 -
背景
在 Linux 中进行文本处理时,有三个非常方便的工具:grep,sed 和 awk。尽管它们是完全不同的工具,但它们的功能在简单情况下似乎重叠。例如,要在文件中查找固定格式的文本并将匹配项打印到标准输出中,我们会发现它们都可以做到。 但是,如果超出简单的练习范围,就会发现 grep 仅适用于简单的文本匹配和打印。 另一方面,除了匹配和打印文本外,sed 还提供其他文本转换命令,例如替换。 最后,awk 是这些工具中功能最强大的一种,它是一种脚本语言,提供了前两个工具所不具备的众多功能。 在开始之前,重要的是要知道本文的目的是使这三个工具之间的区别更加清晰。因此,我们所覆盖的示例只是每种工具的一小部分,尤其是在 sed 和 awk 的情况下。 -
**文本文件
**为了便于讨论,我们定义一个文本文件 log.txt:Timestamp Category Message 1598843202 INFO Booting up system 1598843402 INFO Booting up critical service: Authorization 1598843502 INFO System booted successfully 1598853502 INFO User admin requested access for userlist 1598863888 ERROR User annonymous attempt to access protected resource without credentials 1598863891 INFO System health check status: passed 1598863901 ERROR Requested resource not found 1598864411 INFO User admin logged out -
grep
grep 命令搜索与正则表达式模式匹配的行,并将这些匹配的行打印到标准输出。 当我们需要一种快速的方法来找出给定输入中是否存在特定模式时,这很有用。
4.1 基本语法grep [OPTIONS] PATTERN [FILE...]PATTERN 是一种正则表达式模式,定义了我们想在 FILE 参数指定的文件内容中找到的内容。 OPTIONS 可选参数是用于修改 grep 行为的标志。
**4.2 搜索与正则表达式模式匹配的行
**假设我们要从 log.txt 中提取 ERROR 事件。 我们可以使用 grep 做到这一点:$ grep "ERROR" log.txt 1598863888 ERROR User annonymous attempt to access protected resource without credentials 1598863901 ERROR Requested resource not found原理是 grep 将扫描 log.txt 中的行并将包含 ERROR 的行打印到标准输出中。
**
4.3 取反
**我们可以使用 -v 标志反转匹配:grep -v "INFO" log.txt当我们执行上述命令时,grep 将打印 log.txt 中与 INFO 不匹配的每一行。
**
4.4 打印前行或后行
**有时,我们可能希望在匹配项周围打印前一行或后一行。 要打印匹配文本后五行,我们可以使用标志 -A(after):grep -A 5 ERROR log.txt另一方面,要打印匹配文本前五行,我们可以使用标志 -B(before):
grep -B 5 ERROR log.txt最后,标志-C允许我们打印匹配之前的五行和匹配之后的五行:
grep -C 5 ERROR log.txt**
译者附:
**grep 参数说明:
-v:取反
-A:向后打印
-B:向前打印
-i:忽略大小写
-E:= egrep 启用扩展模式(正则表达式分为基本型 和 扩展型) -
**sed
sed 命令是用于字符流的流编辑器。 它比 grep 功能更强大,因为它提供了更多用于文本处理的选项,包括 sed 最著名的替代命令。5.1 基本语法
**sed 命令具有以下常规语法:sed [OPTIONS] SCRIPT FILE...OPTIONS 是可选标志,可以将其应用于 sed 以修改行为。 接下来,SCRIPT 参数是 sed 脚本,它将在 FILE 参数指定的文件的每一行上执行。
5.2 脚本结构
sed脚本具有以下结构:[addr]X[options]其中 addr 是应用于文本文件各行的条件。 它可以是固定数字,也可以是在处理行之前针对行的内容进行测试的正则表达式。 接下来,X 字符代表要执行的sed命令。 例如,用单个字符表示的替代命令。 最后,可以将 options 传递给 sed 命令以指定其行为。
5.3 sed 实现 grep 的功能
首先,让我们看看如何使用 sed 复制 grep 的功能:sed -n '/ERROR/ p' log.txt默认情况下,sed 会将正在扫描的每一行打印到标准输出流。 要禁用此自动打印,我们可以使用标志 -n。 接下来,它将运行标志 -n 之后的脚本,并在 log.txt 的每一行中查找正则表达式 'ERROR'。 如果匹配,sed 会将行打印到标准输出,因为我们在脚本中使用了 p 命令。 最后,我们传递 log.txt 作为我们希望 sed 处理的文件的名称,作为最后一个参数。
5.4 sed 实现替换功能
sed 的替代命令如下所示:'s/pattern/replacement/'当模式行上存在匹配项时,sed 将用 replacement 替换它。 例如,如果我们想将 log.txt 中的 ERROR 单词替换为 CRITICAL 单词,则可以运行:
sed 's/ERROR/CRITICAL/' log.txt**
5.5 就地修改文件
**如果我们希望 sed 将更改保留在要操作的文件上,则可以使用 -i 标志和后缀。 在进行更改之前,sed 将创建文件备份并将后缀附加到此备份文件名。 例如,当我们运行时:sed -ibackup 's/ERROR/CRITICAL/' log.txt在 sed 将更改应用之前,将复制 log.txt 并将其重命名为 log.txtbackup。**
5.6 限制特定行号
**我们可以限制 sed 命令,以便它只能使用脚本中的 addr 在特定的行号上运行:sed '3 s/ERROR/CRITICAL/' log.txt这将仅在 log.txt 的第3行上运行脚本。 此外,我们可以指定行号范围:
sed '3,5 s/ERROR/CRITICAL/' log.txt在这种情况下,sed 将在 log.txt 的第 3 至 5 行运行脚本。 另外,我们可以使用正则表达式模式指定边界:
sed -n '3,/ERROR/ p' log.txt在这里,sed 将打印从第 3 行开始的 log.txt 行,并在找到与模式 / ERROR / 相匹配的第一行时结束。
-
awk
awk是一种完全成熟的编程语言,可与 Perl 媲美。 它不仅提供用于字符串,算术和时间操纵的大量内置函数,而且还允许用户像定义任何常规脚本语言一样定义自己的函数。 让我们看一下它的一些例子。
6.1 基本语法awk [options] script file它将针对文件中的每一行执行脚本。 脚本的结构展开以后如下所示:
'(pattern){action}'该模式是正则表达式模式,将针对每行输入进行测试。 如果与该模式匹配,则 awk 将在该行上执行在操作中定义的脚本。 如果不存在模式条件,那么将在每一行上执行该动作。**
6.2 awk **实现 grep 的功能****就像我们使用 sed 一样,让我们看一下如何使用 awk 模拟 grep 的功能:
awk '/ERROR/{print $0}' log.txt上面的代码将在 log.txt 文件中找到正则表达式模式 ERROR,并将匹配的行打印到标准输出。**
6.3 awk 替换
**同样,我们可以使用 awk 的内置方法 gsub 将所有 ERROR 替换为 CRITICAL,就像 sed 示例中一样:awk '{gsub(/ERROR/, "CRITICAL")}{print}' log.txtgsub 方法将正则表达式模式和替换字符串作为参数。 然后,awk 将行打印到标准输出。**
6.4 在文档中添加页眉和页脚
**在 awk 中,有一个 BEGIN 块将在开始处理文件的任何行之前执行。 另一方面,还有一个END 块,使我们可以定义在处理完所有行之后应运行的内容。 让我们使用 BEGIN 和 END 块向文本文档添加页眉和页脚:$ awk 'BEGIN {print "LOG SUMMARY\n--------------"} {print} END {print "--------------\nEND OF LOG SUMMARY"}' log.txt LOG SUMMARY -------------- Timestamp Category Message 1598843202 INFO Booting up system 1598843402 INFO Booting up critical service: Authorization 1598843502 INFO System booted successfully 1598853502 INFO User admin requested access for userlist 1598863888 ERROR User annonymous attempt to access protected resource without credentials 1598863891 INFO System health check status: passed 1598863901 ERROR Requested resource not found 1598864411 INFO User admin logged out -------------- END OF LOG SUMMARY**
6.5 列操作
**处理具有行和列结构(CSV 样式)的文档是 awk 真正的亮点。 例如,我们可以轻松地打印第一列和第二列,而跳过我们的 log.txt 的第三列:awk '{print $1, $2}' log.txt**
6.6 自定义分隔符
**默认情况下,awk 将空格作为分隔符。 如果处理文本使用的分隔符不是空格(例如,逗号),则可以使用标志 -F 进行指定:awk -F "," '{print $1, $2}' log.txt**
6.7 算术运算
**awk 执行算术运算的能力使收集有关文本文件的一些数字信息变得容易。 例如,让我们计算 log.txt 中发生 ERROR 事件的次数:awk '{count[$2]++} END {print count["ERROR"]}' log.txtawk 将 Category 列不同值出现的次数存储在变量 count 中。 然后,脚本在末尾打印 ERROR 出现的次数。
**
6.8 数值比较
**作为一种成熟的脚本语言,awk 很容易理解十进制值。 当我们需要脚本将值解释为数字而不是简单的字符串时,这使文本处理变得容易。 例如,我们要使所有日志条目都早于时间戳 1598863888,我们可以使用大于号 >:$ awk '{ if ($1 > 1598863888 ) {print $0} }' log.txt 1598863891 INFO System health check status: passed 1598863901 ERROR Requested resource not found 1598864411 INFO User admin logged ou从输出中,我们可以看到该命令仅打印记录在指定时间戳之后的日志行。
-
**总结
**在本文中,我们从基本介绍 grep,sed 和 awk 开始。 然后,我们展示了 grep 在简单文本扫描和匹配中的用法。 接下来,我们看到了要转换文本时 sed 比 grep 更有用的方法。 最后,我们展示了 awk 如何复制 grep 和 sed 功能,同时还提供了用于高级文本处理的更多功能。
写在后面
其实,很容易可以看出,grep 相当于一个系统封装好的工具,功能简单,使用方便;而 sed 和 awk 相当于比较底层的 api,灵活性高,但是需要一定的上手成本。grep -> sed -> awk 灵活性是逐渐上升的,具体使用哪一个,就看谁能满足你的需求了。
那么,译者能不能提供更贴近实战的例子来说明呢?很遗憾,不能,至少目前不能😂。但是工具就是这样,你只有在见过它,而且明白它大概拿来干嘛的以后,后续遇到适合使用它的场景,你才能知道该它闪亮登场了,不是么?