【问题标题】:Bash: how to certain lines but exclude certain lines in between?Bash:如何在某些行之间排除某些行?
【发布时间】:2019-05-30 18:48:34
【问题描述】:

我有一个如下所示的文件:

a: 0
a: 0
a: 0
a: 1
b: 1
c: 1
d: 1
e: 1
f: 1
a: 2
b: 2
c: 2
d: 2
e: 2
f: 2
a: 3
b: 3
c: 3
d: 3
e: 3
f: 3
c: 4
c: 4
c: 4

我想捕获并输出ac 形式的所有<a line><anything other than an a or c line><c line> 行,因此输出如下所示:

a: 1
c: 1

a: 2
c: 2

a: 3
c: 3

请注意,开头的a: 0 行和结尾的c: 4 行都没有被捕获,因为它们不遵循我提到的模式。另请注意,ac 行之间的 b 行已被删除。

我一直在尝试使用 Bash 的 pcregrep 进行环视,但还没有找到解决方案。有什么想法吗?

谢谢!

【问题讨论】:

  • 为什么用pcre 过于复杂,你试过grep -E '^[ac]' 吗?
  • 你尝试了什么?和bash 有什么关系?你在哪里找到bash 提供pcregrep?发布您迄今为止所做的尝试
  • 为什么输出的两行之间都有空格?
  • @PS。我编辑了我原来的帖子。我之前遗漏了一些信息。你是对的,你建议的正则表达式解决了我最初写的问题,所以我投了赞成票。
  • @Inian 我更新了我的原始帖子,我遗漏了一些信息。 Re bash,我正在 OS X(终端)上的 bash shell 中编写 pcregrep 命令。到目前为止,我尝试过的一个例子是 pcregrep -M '^a(?=(^b))^c' ,我试图匹配以 'a' 开头的具有 'b' 的行在它前面的一行和一个“c”行,并且只包括“a”和“c”行。

标签: regex bash grep pcre pcregrep


【解决方案1】:

使用 awk

试试:

$ awk -F: '$1=="a"{aline=$0} $1=="c"{if(aline)print aline ORS $0 ORS; aline=""}' file
a: 1
c: 1

a: 2
c: 2

a: 3
c: 3

工作原理

默认情况下,awk 一次读取一行。

  • -F:

    这告诉 awk 使用 : 作为字段分隔符。

  • $1=="a"{aline=$0}

    每次观察到a 行时,将该行保存在变量aline 中。

  • $1=="c"{if(aline)print aline ORS $0 ORS; aline=""}

    每次观察到c 行,检查我们是否有一个非空的aline。如果是这样,打印aline 和当前行,用换行符分隔。另外,将aline 设置回一个空字符串。

多行版本

对于那些喜欢将命令分散在多行中的人:

awk -F: '
    $1=="a"{
        aline=$0
    }

   $1=="c"{
        if(aline)
            print aline ORS $0 ORS
        aline=""
    }' file

使用 sed

$ sed -n '/^a/h; /^c/{x;/^a/{p;x;s/$/\n/;p};h}' file
a: 1
c: 1

a: 2
c: 2

a: 3
c: 3

工作原理

  • -n

    这告诉 sed 除非我们明确要求,否则不要打印任何内容。

  • /^a/h

    只要我们有以a 开头的行,我们就会将其保存到保留空间。

  • /^c/{ x; /^a/{ p; x; s/$/\n/; p}; h}

    只要我们有以c 开头的行,我们:

    • 我们将模式空间与保持空间交换 (x)。

    • 如果新的模式空间以a开头,那么我们打印(p),然后再次交换(x),在新模式空间(@ 987654343@) 并打印 (p)。

    • 最后,我们将当前模式空间(以c 开头)保存到保持空间。

【讨论】:

  • 谢谢!我以前没有使用过 awk,但我会尝试使用它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-02
  • 2022-01-16
  • 1970-01-01
  • 2022-12-17
  • 1970-01-01
  • 2021-10-30
相关资源
最近更新 更多