【问题标题】:How can I print multiple patterns on separate lines如何在不同的行上打印多个图案
【发布时间】:2019-09-07 18:20:06
【问题描述】:

我有一个想用 bash 处理的文件。可以使用 awk、sed 或 grep 或类似的。该文件在一行中有多次出现。我想提取这两次出现之间的所有内容并将输出分别打印在单独的行上。

我已经尝试过使用这个:

cat file.txt | grep -o 'pattern1.*pattern2'

但这会打印从 pattern1 到最后一个匹配 pattern2 的所有匹配项。

$ cat file.txt
pattern1 this is the first content pattern2 this is some other stuff pattern1 this is the second content pattern2 this is the end of the file.

我想得到:

pattern1 this is the first content pattern2
pattern1 this is the second content pattern2

【问题讨论】:

  • 您的输入中可以包含foo pattern1 bar pattern2pattern1 foo pattern1 bar pattern2pattern1 foo pattern2 bar pattern2 吗?如果是这样,请在您的问题中包含这些案例并显示每个案例的预期输出。
  • 我重新打开了这个,因为另一个问题是以前作为 (stackoverflow.com/questions/3027518/…) 的副本关闭的另一个问题是询问跨多行匹配,这是一个比行内更容易解决的问题,它没有'不包含标准 UNIX 工具的解决方案,仅适用于带有实验性 -P 选项的 perl 或 GNU grep,并且有更好(更简单、更高效、更便携、更健壮)的跨行匹配解决方案。

标签: bash awk sed grep


【解决方案1】:

试试 gnu sed:

 sed -E 's/(pattern2).*(pattern1)(.*\1).*/\1\n\2\3/' file.txt

【讨论】:

  • 对于不包含在 OP 示例输入中的 extract everything between these two occurrences 的某些情况,如果这些情况可能发生,则 I've asked 会失败。
  • 您的示例仅打印两种模式之间的第一个字符串,但跳过第二个字符串。是的,我在这些模式之间有多个特殊字符,也是为了更好地理解,有时我不知道 pattern1 和 pattern2 之间的字符串是出现一次、两次、三次还是 x 次。稍后我会得到一段实际的示例代码来说明我的意思。
  • 不,不要随便抓一段代码然后扔给我们尝试通过。花点时间精心创建一个minimal reproducible example,展示您问题的各个方面,我们可以测试潜在的解决方案。
【解决方案2】:

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

sed -n '/pattern1.*pattern2/{s/pattern1/\n&/;s/.*\n//;s/pattern2/&\n/;P;D}' file

将选项-n 设置为显式打印。

仅处理包含pattern1 后跟pattern2 的行。

pattern1 前添加一个换行符。

删除并包括引入的换行符。

pattern2 之后添加一个换行符。

打印模式空间的第一行,删除并重复。

【讨论】:

    【解决方案3】:

    如果您无法使用支持环视的工具,这种方法虽然很长,但可以在任何 UNIX 机器上使用标准工具稳健地工作:

    awk '{
        gsub(/@/,"@A"); gsub(/{/,"@B"); gsub(/}/,"@C"); gsub(/pattern1/,"{"); gsub(/pattern2/,"}")
        out = ""
        while( match($0,/{[^{}]*}/) ) {
            out = (out=="" ? "" : out ORS) substr($0,RSTART,RLENGTH)
            $0 = substr($0,RSTART+RLENGTH)
        }
        $0 = out
        gsub(/}/,"pattern2"); gsub(/{/,"pattern1"); gsub(/}/,"@C"); gsub(/{/,"@B"); gsub(/@A/,"@")
    } 1' file
    

    上面的方法是通过创建输入中不存在的字符(首先将这些字符 {} 更改为其他一些字符串 @B@C),因此它可以在否定字符类来查找目标字符串,然后它将所有更改的字符返回到它们的原始值。这里有一些印刷品,以使每一步发生的事情更加明显:

    awk '{
        print "1): " $0 ORS
        gsub(/@/,"@A"); gsub(/{/,"@B"); gsub(/}/,"@C"); gsub(/pattern1/,"{"); gsub(/pattern2/,"}")
        print "2): " $0 ORS
        out = ""
        while( match($0,/{[^{}]*}/) ) {
            out = (out=="" ? "" : out ORS) substr($0,RSTART,RLENGTH)
            $0 = substr($0,RSTART+RLENGTH)
        }
        $0 = out
        print "3): " $0 ORS
        gsub(/}/,"pattern2"); gsub(/{/,"pattern1"); gsub(/}/,"@C"); gsub(/{/,"@B"); gsub(/@A/,"@")
        print "4): " $0 ORS
    } 1' file
    1): pattern1 this is the first content pattern2 this is some other stuff pattern1 this is the second content pattern2 this is the end of the file.
    
    2): { this is the first content } this is some other stuff { this is the second content } this is the end of the file.
    
    3): { this is the first content }
    { this is the second content }
    
    4): pattern1 this is the first content pattern2
    pattern1 this is the second content pattern2
    
    pattern1 this is the first content pattern2
    pattern1 this is the second content pattern2
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-15
      • 2011-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多