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

Posted

技术标签:

【中文标题】如何使用 sed 或 awk 正确查找和替换多行文本?【英文标题】:How to properly find and replace a multiline text using sed or awk? 【发布时间】:2020-04-25 07:11:15 【问题描述】:

尝试替换以下文本时,我收到错误:

sed -i "s/  type pulse
  fallback "sysdefault"
  hint 
    show on
    description "Default ALSA Output (currently PulseAudio Sound Server)"
  /  type plug
      slave.pcm hw/g" .asoundrc

未找到匹配项:(当前为 PulseAudio 声音服务器)\n / 类型 插头\n slave.pcm hw/g

我已经尝试使用 \ 转义 " 或将它们交换为 ' 但错误是:

sed: -e expression #1, char 14: unterminated `s' command

问题与空白/新行有关吗?使用 sed、awk 或 perl 最简单的方法是什么?非常感谢!

【问题讨论】:

【参考方案1】:

sed 中的命令由换行符分隔。要匹配多行字符串,您可以使用N 命令读取模式空间中的多行,然后使用\n 正则表达式匹配它们以匹配换行符。如果未找到匹配项,则必须使用保留空间进行洗牌:保留模式空间,打印所有内容直到换行符,使用保留空间切换模式,从模式中删除所有内容直到第一个换行符,阅读下一行,重复。

这将是一些事情:

sed '
  : restart
  N;N;N;N;N; # read six lines, we need that many
  : loop
      # match six lines
      /  type pulse\n  fallback "sysdefault"\n  hint \n    show on\n    description "Default ALSA Output (currently PulseAudio Sound Server)"\n  /
           # replace them
           s//    type plug\n      slave.pcm hw/
           # print and start over
           n ; b restart
       
       # hold, print leading line, change, remove leading line
       h ; s/\n.*// ; p ; x ; s/[^\n]*\n//
       # append next line and loop
       N
  b loop
'

由于编写这样的脚本很难(对大多数人来说;),有些人只使用 GNU sed -z 选项:

sed -z 's/  type pulse\n  fallback "sysdefault"\n  hint \n    show on\n    description "Default ALSA Output (currently PulseAudio Sound Server)"\n  /  type plug\n      slave.pcm hw/g'

请注意,我认为在 s 命令内的替换字符串中使用 \n 无论如何都是 GNU 扩展。

【讨论】:

哇,这个大例子太棒了!您推荐哪些资源来学习 sed 和 awk?非常感谢您的详细解释和两个答案! sed introduction by Bruce Barnett 仍然是谷歌中第一个出来的并且很棒。有一天,它只是让我“点击”了什么是模式和保持空间——在理解了这一点之后,它只是脚本。 grymoire.com也有awk介绍。【参考方案2】:

在多行模式下使用perl:

perl -i -0 -pe '
    s/type pulse.*PulseAudio Sound Server\)/  type plug\n    slave.pcm hw/s
' file

 输出

type plug
slave.pcm hw

注意

你真正想要达到什么目的?也许有更好的方法。

【讨论】:

非常有趣!我的输入返回了一个多余的 " 和 。即使使用 \,我也无法删除 ,尝试了带和不带空格但它不起作用... perl -i -0 -pe 's/type pulse.* PulseAudio Sound Server)\"/ type plug\n slave.pcm hw/s ' [关于注释]我正在尝试自动化音频文件编辑,但是由于我不知道在linux上是否有差异只有当我找到这个确切的块代码时,我才需要更改发行版。感谢您的代码!【参考方案3】:

正如其他人评论的那样,sed 逐行处理文件并且无法处理 多行作为默认行为。一个可能的解决方法是啜饮 在第一阶段使用N 命令的模式空间中的所有行 并在下一步中执行替换。那么怎么样:

sed '
:l
N
$!b l
s/ *type pulse\n *fallback "sysdefault"\n *hint \n *show on\n *description "Default ALSA Output (currently PulseAudio Sound Server)"\n */  type plug\'$'\n''  slave.pcm hw/g' .asoundrc

如果文件过大,吞食所有文件可能效率低下 但现在大多数情况下都没有问题。

【讨论】:

以上是关于如何使用 sed 或 awk 正确查找和替换多行文本?的主要内容,如果未能解决你的问题,请参考以下文章

如何根据来自不同命令的多行打印输出的输入将文本文件内容替换为“sed”或“awk”?

如何使用 sed/awk 或其他工具辅助查找和替换 12GB 的颠覆转储文件

sed或awk:从选定的多行替换 n

如何使用“sed”或“awk”替换url参数查询字符串

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

awk && sed ====积累取ip以及sed 查找替换