使用 sed 替换多行

Posted

技术标签:

【中文标题】使用 sed 替换多行【英文标题】:Replacing multiple lines using sed 【发布时间】:2022-01-19 18:13:50 【问题描述】:

美好的一天!

我试图弄清楚hold spacepattern spacesed 中的工作原理,以便我可以用它来替换多个字符串。

例如,如果要将第一行和第二行替换为NEW STRING

echo -e "aa\nbb\ncc\ndd\n"
aa
bb
cc
dd

为了得到这样的STDOUT:

NEW STRING
NEW STRING
cc
dd

我正在尝试做类似的事情:

echo -e "aa\nbb\ncc\ndd\n" | sed -e 'commands'

我知道可以这样做:

echo -e "aa\nbb\ncc\ndd\n" | tr '\n' '\0' | sed -e 's#aa#NEW STRING#;s#bb#NEW STRING#' | tr '\0' '\n'
NEW STRING
NEW STRING
cc
dd

但是不使用tr怎么解决这个问题呢?

您能否提出一个我们不知道行号的案例?我们只知道aabb 之后。

【问题讨论】:

【参考方案1】:

sed 命令接受一系列要操作的行:

$ printf "%s\n" aa bb cc dd | sed '1,2s/.*/NEW STRING/'
NEW STRING
NEW STRING
cc
dd

有些像s 处理范围内的单个行,有些则将整个范围视为一个块以将命令应用于:

$ printf "%s\n" aa bb cc dd | sed '1,2c\
NEW STRING'
NEW STRING
cc
dd

例如,一行是aaa,另一行是bbb。我们知道 aaa 在 bbb 之前,但我们不知道他们在文件中的编号。

我总结的一种方法(可能会有更好的方法;并且仅使用 GNU sed 进行了测试)

$ printf "%s\n" qq rr aa bb cc aa xx dd |
  sed '/^aa$/N; /^aa\nbb$/s/.*/NEW STRING\nNEW STRING/; p; d; P; D'
qq
rr
NEW STRING
NEW STRING
cc
aa
xx
dd

如果当前行是aaN 将下一行追加到当前模式空间。如果它现在是 aa\nbb,则用两行 NEW STRING 行替换它,打印出模式空间,将其删除并重新开始。如果模式空间有其他内容,则打印出第一个换行符之前的所有内容,从模式空间中删除该文本,然后从 N 读取的第二行重新开始。

【讨论】:

如果我们不知道行号,但我们知道需要用正则表达式替换行怎么办?例如,一行是aaa,另一行是bbb。我们知道aaabbb 之前,但我们不知道文件中它们的编号。 bbb 位于 aaa 之后。谢谢! @alex2020:如果您自己指定这些要求会更好。 @alex2020 查看编辑。 最后的解决方案可能是sed '/^aa/N;/^bb/M!P;D;s/.*/new string/p' file?【参考方案2】:

如果目标是试验模式空间和保持空间,那么这就是一个例子:

echo -e "aa\nbb\ncc\ndd" | sed '1 s/.*/NEW STRING/; h; 2g'

输出:

新字符串 新字符串 抄送 dd

将第一行替换为 NEW STRING,然后复制模式空间以保留空间 (h)。在第二行将保持空间复制到模式空间 (g)。

【讨论】:

以上是关于使用 sed 替换多行的主要内容,如果未能解决你的问题,请参考以下文章

在 bash 脚本中使用 sed 替换多行模式

如何使用 sed 或 awk 正确查找和替换多行文本?

使用sed用多行替换一个单词?

使用 grep 和 sed 在 shell 中查找和替换同一文件中的多行

使用sed进行多行替换

sed匹配多行并替换其中的内容