Sed 实用技巧
sed 实用技巧:常见任务处理
Section titled “sed 实用技巧:常见任务处理”sed 是一个多功能的工具,通常有多种方法来解决文本处理问题。本节提供了一些“技巧”集合——使用 sed 可以完成的常见任务,通常模拟其他标准 Unix 工具的功能。这些示例展示了 sed 的强大和灵活性。对于某些示例,我们将使用通用的 input.txt 或 data.txt。除非另有说明,否则假设 books.txt 指的是每条目占一行的格式。
模拟 cat (连接并显示文件)
Section titled “模拟 cat (连接并显示文件)”方法 1:使用默认行为(不带命令)。
$ sed '' books.txt方法 2:显式打印每一行。
$ sed -n 'p' books.txt这两个命令都会显示 books.txt 的全部内容。第二个示例中的 -n 选项抑制了自动打印,因此需要 p (打印) 命令。
从文件中删除所有空行:
$ echo -e "Line #1\n\n\nLine #2" | sed '/^$/d'输出:
Line #1Line #2解释:^$ 是一个匹配空行的正则表达式(行首 ^ 后紧跟着行尾 $)。d 命令从模式空间中删除此类行。
或者,只打印非空行:
$ echo -e "Line #1\n\n\nLine #2" | sed -n '/^$/!p'输出:
Line #1Line #2解释:!p 意味着如果行 不 匹配模式 /^$/,则打印该行。
删除单行注释(例如,C++ 代码中的)
Section titled “删除单行注释(例如,C++ 代码中的)”考虑一个简单的 C++ 文件 hello.cpp:
#include <iostream>using namespace std;
int main(void){ // Displays message on stdout. cout << "Hello, World !!!" << endl; return 0; // Return success.}要删除 // 注释:
$ sed 's|//.*||' hello.cpp输出:
#include <iostream>using namespace std;
int main(void){ cout << "Hello, World !!!" << endl; return 0;}解释:s|//.*|| 将模式 //.*(双斜杠 // 后跟行尾 . 的任意字符 *)替换为空字符串 ||。注意:这是一种简单的方法,可能无法正确处理字符串内部的 // 或复杂代码中的块注释。对于稳健的解析,专用的代码检查器 (linters) 或解析器 (parsers) 更好。
在特定行前添加注释
Section titled “在特定行前添加注释”假设 script.sh 包含 shell 命令。要通过在其前添加 # 来注释掉第 3 到第 5 行:
$ sed '3,5s/^/#/' script.sh转换后的 script.sh 示例输出(未显示原始内容):
#!/bin/bashpwd#hostname#uname -a#lswho解释:3,5 是一个地址范围,选择了第 3 到第 5 行。s/^/#/ 将行首 (^) 替换为 #。
模拟 wc -l (计算行数)
Section titled “模拟 wc -l (计算行数)”$ sed -n '$=' books.txt输出(假设 books.txt 有 6 行):
6解释:$ 定位到最后一行。= 打印其行号。-n 抑制默认的行打印。
模拟 head (显示前 N 行)
Section titled “模拟 head (显示前 N 行)”要显示 long_file.txt 的前 10 行:
$ sed '10q' long_file.txt解释:q 命令告诉 sed 在处理第 10 行后退出。对于大文件,这通常比 sed -n '1,10p' 更高效。
模拟 tail -1 (显示最后一行)
Section titled “模拟 tail -1 (显示最后一行)”$ sed -n '$p' books.txt输出 (books.txt 的最后一行):
6) A Game of Thrones, George R. R. Martin, 864解释:$ 定位到最后一行,p 打印它,-n 抑制其他输出。
模拟 dos2unix (将 CRLF 转换为 LF)
Section titled “模拟 dos2unix (将 CRLF 转换为 LF)”DOS/Windows 使用回车 + 换行 (\r\n) 作为换行符,而 Unix 使用换行符 (\n)。要进行转换:
$ sed 's/\r$//' dos_file.txt > unix_file.txt解释:s/\r$// 删除行尾 ($) 的回车符 (\r)。注意:某些 sed 版本可能需要输入 ^M(在许多终端中按 Ctrl+V, Ctrl+M)而不是 \r,如果 \r 未被识别为特殊转义符。
模拟 unix2dos (将 LF 转换为 CRLF)
Section titled “模拟 unix2dos (将 LF 转换为 CRLF)”$ sed 's/$/\r/' unix_file.txt > dos_file.txt解释:s/$/\r/ 将行尾 ($) 替换为回车符 (\r)。sed 在打印时会自动添加换行符 (\n)。
模拟 cat -E (在行尾显示 $)
Section titled “模拟 cat -E (在行尾显示 $)”$ sed 's/$/$/' input.txt解释:s/$/$/ 将行尾(由 $ 匹配)替换为字面字符 $。
模拟 nl (给行编号)
Section titled “模拟 nl (给行编号)”$ sed '=' input.txt | sed 'N; s/\n/\t/'示例输出(对于包含两行 “Line A” 和 “Line B” 的 input.txt)
1 Line A2 Line B解释:第一个 sed '=' input.txt 打印行号,然后是换行符,然后是行内容。第二个 sed 命令处理这个输出:N 将下一行(实际内容行)附加到模式空间(它包含行号)。s/\n/\t/ 将行号和内容之间的换行符替换为制表符 (\t)。
模拟 cp (复制文件)
Section titled “模拟 cp (复制文件)”$ sed 'w new_copy.txt' original.txt如果只想写入文件而不打印到标准输出:
$ sed -n 'w new_copy.txt' original.txt解释:w new_copy.txt 命令将模式空间的内容写入 new_copy.txt,对处理的每一行都执行此操作。
模拟 expand (将制表符转换为空格)
Section titled “模拟 expand (将制表符转换为空格)”将每个制表符 (tab) 转换为 8 个空格(expand 的常见默认设置):
$ sed 's/\t/ /g' file_with_tabs.txt解释:s/\t/ /g 将每个制表符 (\t) 替换为八个空格,并对每一行进行全局 (g) 替换。
模拟 tee (输出到标准输出和文件)
Section titled “模拟 tee (输出到标准输出和文件)”$ sed 'p; w output_file.txt' input.txt如果默认打印被 -n 抑制(例如,使用了其他命令):
$ sed -n 'p; w output_file.txt' input.txt解释:p 将当前的模式空间打印到标准输出。w output_file.txt 将模式空间写入 output_file.txt。如果使用不带 -n 的 sed,p 可能会导致重复打印,除非脚本逻辑设计得非常小心。sed 'w output_file.txt' input.txt 也会起作用,它默认打印到标准输出并写入文件。
模拟 cat -s (将多个空行压缩为一个)
Section titled “模拟 cat -s (将多个空行压缩为一个)”将连续两个或更多空行减少为单个空行:
$ sed '/^$/{N; /\n$/D;}' input_with_blanks.txt示例:输入 A\n\n\nB 变为 A\n\nB。
解释:这是一种常见的用法。如果一行是空的 (/^$/),N 附加下一行。如果模式空间现在仅包含两个换行符(\n$, 实际上模式是 original_empty_line\nnext_line,所以如果 next_line 也是空的,模式空间看起来就是 \n),D 会删除直到第一个换行符的内容并重新启动循环。这有效地处理了成对的空行。为了完美模拟 cat -s,正确处理所有边缘情况和任意数量的空行,在 POSIX sed 中可能需要更复杂的脚本或多遍处理,或者可以依赖 GNU sed 扩展。
模拟 grep (打印匹配模式的行)
Section titled “模拟 grep (打印匹配模式的行)”$ sed -n '/pattern/p' input.txt解释:-n 抑制默认输出。/pattern/p 打印匹配 pattern 的行。
模拟 grep -v (打印不匹配模式的行)
Section titled “模拟 grep -v (打印不匹配模式的行)”$ sed -n '/pattern/!p' input.txt解释:/pattern/!p 打印不 (!) 匹配 pattern 的行。
模拟 tr (转换字符)
Section titled “模拟 tr (转换字符)”将所有大写字母 ABC 转换为小写字母 abc:
$ echo "ABC TEST" | sed 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'输出:
abc test解释:y/source_chars/dest_chars/ 命令转换字符。source_chars 中的每个字符都会被 dest_chars 中对应位置的字符替换。