【问题标题】:regex command line with single-line flag带有单行标志的正则表达式命令行
【发布时间】:2020-12-02 18:12:48
【问题描述】:

我需要在bash 脚本中使用正则表达式来替换文件中可能位于多行的文本。
我会在我知道的其他正则表达式引擎中将s 作为标志传递,但我很难使用 bash。

sed 据我所知不支持此功能。
perl 显然支持,但我不能让它在一个班轮中工作 perl -i -pe 's/<match.+match>//s $file

示例文本:

DONT_MATCH

<match some text here
    and here
match>

DONT_MATCH

【问题讨论】:

  • 请在您的问题中添加示例输入(无描述、无图像、无链接)以及该示例输入所需的输出(无评论)。
  • 到目前为止,您对sed 进行了哪些尝试?如果您有 GNU sed,那么您可能正在寻找类似 @​​987654329@ 的东西。

标签: regex perl sed


【解决方案1】:

默认情况下,. 不匹配换行符。 s 只是让. 匹配任何字符。

您一次读取一行文件,因此您不可能匹配跨越多行的内容。使用-0777 将整个输入视为一行。

perl -i -0777pe's/<match.+match>//s' "$file"

【讨论】:

  • 我认为 s(单行模式)正是这样做的。将输入字符串视为单行,因此也匹配换行符。
  • 它确实将整个输入视为一行(通过使. 不特别对待LF),但它仍然无法匹配您尚未阅读的内容! $_,与您匹配的对象,从未同时包含 &lt;match some text here 和 match&gt;
【解决方案2】:

这可能对你有用(GNU sed):

sed '/^<match/{:a;/match>$/!{N;ba};s/.*//}' file

收集从 &lt;match 开头到结尾 match&gt; 的一组行,然后将它们替换为空。

注意这将对整个文件中的所有此类集合起作用,并且文件结束条件不会影响结果。要仅对第一个采取行动,请使用:

sed '/^<match/{:a;/match>$/!{N;ba};s/.*//;:b;n;bb}' file

仅对第二个此类集合使用:

sed -E '/^<match/{:a;/match>$/!{N;ba};x;s/^/x/;/^(x{2})$/{x;s/.*//;x};x}' file

可以定制正则表达式/^(x{2})$/ 以进行更复杂的匹配,例如/^(x|x{3,6})$/ 将匹配第一和第三到第六个集合。

【讨论】:

    【解决方案3】:

    使用 GNU sed:

    $ sed -z 's/<match.*match>//g' file
    DONT_MATCH
    
    
    
    DONT_MATCH
    

    使用任何 sed:

    $ sed  'H;1h;$!d;x; s/<match.*match>//g' file
    DONT_MATCH
    
    
    
    DONT_MATCH
    

    上述两种方法都将整个文件读入内存。如果您有一个大文件(例如千兆字节),您可能需要一种不同的方法。

    详情

    使用 GNU sed,-z 选项读取以 NUL 作为记录分隔符的文件。对于从不包含 NUL 的文本文件,这具有读取整个文件的效果。

    对于普通的sed,可以通过以下步骤读入整个文件:

    • H - 追加当前行以保留空间
    • 1h - 如果这是第一行,则覆盖保留空间 有了它
    • $!d - 如果这不是最后一行,删除模式空间 并跳到下一行。
    • x - 交换保持和模式空间以放入整个文件 模式空间

    【讨论】:

    • 虽然所有答案都有效,但我选择了这个,因为 sed 是已在同一脚本中使用的工具,并且是最容易阅读的代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-21
    • 2020-05-21
    • 2021-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多