AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 668793
Accepted
ChennyStar
ChennyStar
Asked: 2021-09-14 01:54:21 +0800 CST2021-09-14 01:54:21 +0800 CST 2021-09-14 01:54:21 +0800 CST

sed :以最后一次出现的模式结束范围(贪婪范围)

  • 772

获取以下文件:

$ cat f1
stu vwx yza
uvw xyz abc
abc def ghi
def ghi jkl
ghi jkl mno
jkl mno pqr
mno pqr stu
pqr stu vwx
stu vwx yza

要打印从第一个包含abc到第一个包含mnoGNU的所有行sed:

$ sed -n '/abc/,/mno/p' f1
uvw xyz abc
abc def ghi
def ghi jkl
ghi jkl mno

我怎样才能打印所有行,直到最后一个包含mno,例如我怎样才能得到以下结果:

uvw xyz abc
abc def ghi
def ghi jkl
ghi jkl mno
jkl mno pqr
mno pqr stu

换句话说,有没有办法让 GNUsed的范围选择变得贪婪?

更新

在我的设置中:

  • 如果mno丢失,它应该打印出所有内容,直到文件结束。
  • mno不能发生在第一个之前abc。
  • 总是至少有一个abc,并且abc永远mno不会在同一条线上

编辑 我只是在开头添加了一个虚拟stu vwx yza行,以便文件不以包含的行开头abc(以避免从第一行开始的解决方案 - 它们应该从其中包含的第一行开始abc)

awk text-processing
  • 9 9 个回答
  • 1092 Views

9 个回答

  • Voted
  1. Inian
    2021-09-14T02:33:42+08:002021-09-14T02:33:42+08:00

    awk如果它是一个选项,你可以使用。您可以标记模式开始和模式停止的行,并在文件的一次传递中打印这些行(涉及存储从第一行开始的行,abc直到缓冲区中的最后一行)

    awk '/abc/ && !start {
      start = NR
    }
    /mno/ {
      stop = NR
    }
    start { line[NR] = $0 }
    END {
      if ( !stop ) {
        stop = NR
      }
      for ( s = start; s <= stop; s++ )
        print line[s]
    }' file
    

    请注意,当起始模式不存在时,这将不起作用,仅打印一系列空白行。

    • 5
  2. Best Answer
    nezabudka
    2021-09-14T03:51:40+08:002021-09-14T03:51:40+08:00
    sed '/abc/,$!d;0,/mno/b;:1;/mno/b;$d;N;b1' file
    

    工作算法:
    使用两个地址范围。
    第一个/abc/,$!d;删除直到第一个模式匹配的所有内容。与模式匹配
    的第二个,将每一行缓冲区(模式空间)发送到输出绕过剩余的脚本,从而防止在文件中找不到模式时删除。 脚本的其余部分循环工作。在编辑器缓冲区中,添加行直到发生模式匹配。如果遇到模式,则将整个缓冲区发送到输出,绕过脚本的其余部分。如果不匹配,则在最后一行删除缓冲区。0,/mno/b;/mno/
    :1;/mno/b;$d;N;b1/mno/

    • 5
  3. AdminBee
    2021-09-14T03:18:27+08:002021-09-14T03:18:27+08:00

    另一种awk缓冲较少的解决方案:

    awk '!f&&/abc/{f=1} f==1; f==2{buf=buf $0 ORS} f&&/mno/{f=2; printf "%s",buf; buf=""}' input.txt
    
    • 这将打印从第一次出现abc(将标志设置f为 1)开始的所有内容,包括第一次出现mno. f==1规则块之外的语句指示只要awk设置为 就打印当前f行1。
    • 然后,每次出现 后的所有行的内容mno(f现在的值为 2)存储在缓冲区中buf,该缓冲区在下一次出现时打印并清除mno。为了确保我们正确处理 firstmno出现在 first之前的情况abc,我们要求f在应用该逻辑之前至少将其设置为 1。

    因此,它将最多存储两次出现之间的文本mno,或者最后一次出现mno和文件结尾(只有后一部分永远不会被打印)。

    如果你想用内存效率交换速度,下面的两遍方法根本不依赖缓冲:

    awk 'FNR==NR{if (/abc/&&!start) {start=FNR} else if (/mno/) {end=FNR}; next} FNR>=start&&(!end||FNR<=end)' input.txt input.txt
    

    这将处理文件两次(因此它被指定两次作为参数)。

    • 第一次,当FNR每个文件的行计数器等于NR全局行计数器时,我们查找 的第一次出现abc和最后一次出现mno,并将它们的行号分别存储在start和end中。
    • 在第二遍中,只要FNR计数器在(并包括)start结束之间(或者只是如果end它大于/等于未设置),我们就会打印行。startend
    • 4
  4. terdon
    2021-09-14T02:08:56+08:002021-09-14T02:08:56+08:00

    我不认为 sed 可以变得贪婪,不。一种可能的解决方法,简单但效率低,是处理文件两次。一次获取行范围,另一个进行打印。例如:

    $ perl -lne '$s||=$. if /abc/; $e=$. if /mno/; }{ print "$s $e"' file | 
        while read start end; do sed -n "$start,${end}p" file; done
    abc def ghi
    def ghi jkl
    ghi jkl mno
    jkl mno pqr
    mno pqr stu
    

    或者,如果您想处理缺少一种或两种模式的情况:

    perl -lne '$s||=$. if /abc/; $e=$. if /mno/; }{ $s||=1; $e||=$.; print "$s $e"' file | 
        while read start end; do sed -n "$start,${end}p" file; done
    

    如果abc没有找到,它将从文件的开头打印。如果mnc未找到,它将从abc(或开头,如果abc不存在)打印到结尾。如果没有找到任何模式,它当然不会打印任何内容。

    • 3
  5. Philippos
    2021-09-14T02:31:50+08:002021-09-14T02:31:50+08:00

    收集行,直到一个mno序列使它们准备好打印:

    sed -e '/abc/,$!d;:loop' -e'/mno/{p;d;}' -e '$d;N;bloop'
    
    • /abc/,$!d d删除除从第一abc行到结尾的范围之外的所有内容。这也处理了根本没有的情况abc。
    • 然后我们需要:loop.
    • /mno/{p;d;}如果mno模式空间中有,请p重新开始。
    • $d如果我们到达没有 的最后一行mno,d则删除缓冲区中的所有内容。不幸的是,这意味着没有输出,如果根本没有mno的话。
    • 否则附加Next 行并继续循环。
    • 2
  6. Philippos
    2021-09-14T05:02:57+08:002021-09-14T05:02:57+08:00

    您可以收集所有行,从abc保留空间中的行开始,然后使用贪婪的性质.*删除最后一个之后的所有内容mno:

    sed '/abc/,$!d;H;$!d;x;s/\n//;s/\(.*mno[^\n]*\).*/\1/'
    
    • /abc/,$!d是d删除第一行之前的所有内容abc(或整个文件,如果根本没有abc行)
    • H;$!d是在保存空间中收集整个文件的经典模式(请注意,这对于非常大的文件可能是一个问题)
    • 我们x更改缓冲区而不是使用g以避免复制大缓冲区
    • s/\n//在开头删除错误的换行符,通过附加到空的保留空间产生
    • s/\(.*mno[^\n]*\n\).*/\1/删除最后 mno一行之后的所有内容(或根据要求打印整个剩余文件,如果没有mno行)。请注意,这[^\n]不是 POSIX,仅适用于 GNU 等某些版本sed。
    • 2
  7. jubilatious1
    2021-09-15T14:58:18+08:002021-09-15T14:58:18+08:00

    使用 Raku(以前称为 Perl_6)

    raku -e '(S:g/ <( ^ .*? $$ \n )> ^^ .*? abc .*? $$ // andthen S:g/ ^^ .* mno .*? $$  <( .*? $)> //).put for lines.join("\n");'
    

    样本输入:

    1. stu vwx yza
    2. uvw xyz abc
    3. abc def ghi
    4. def ghi jkl
    5. ghi jkl mno
    6. jkl mno pqr
    7. mno pqr stu
    8. pqr stu vwx
    9. stu vwx yza
    10. mno pqr stu
    11. xyz xyz xyz
    

    样本输出:

    2. uvw xyz abc
    3. abc def ghi
    4. def ghi jkl
    5. ghi jkl mno
    6. jkl mno pqr
    7. mno pqr stu
    8. pqr stu vwx
    9. stu vwx yza
    10. mno pqr stu
    

    请注意,当输入第 11 行样本输入时,样本输出是第 2 到第 10 行的返回。此外,当样本输入被截断为仅第 1 到第 10 行(即mno在最后一行)时,上面的 Raku 代码仍然(正确地)返回第 2 到第 10 行。

    感谢 @ImHere 和 @ChennyStar 在评论中鼓励我提出更强大的 Raku 解决方案。

    https://raku.org

    • 1
  8. guest_7
    2021-09-16T16:15:49+08:002021-09-16T16:15:49+08:00

    使用GNU sed 注意:根据 OP,第一行 abc 没有 mno,因此我们可以在下面的 sed 代码中利用这一事实。

    sed -e '
      /abc/,$!d
      /mno/{h;b;}
      $!{N;s/^/\n/;D;}
      x;/./d;x
    ' file
    

    在这种方法中,我们使用 slurp 模式-z读取模式空间中的完整文件。然后我们删除直到包含 abc 的第一行之前。之后使用正则表达式的贪婪到达最后一个 mno 行。

    sed -Ez '
      s/abc/\x0&/
      s/.*\n(.*)\x0/\1/
      s/(.*mno[^\n]*\n).*/\1/
    ' file
    

    还有一种方法是两遍方法,我们记录第一个 abc 行和最后一个 mno 行的行号。如果没有 mno 存在,我们在它的位置填写 $。然后使用这两个数字我们构造一个 sed 命令 begin,end p;endq

    sed -n '/abc/{=;:a;n;/mno/=;ba}' file |
    sed -En '
      1{h;$s/.*/$/;}
      ${x;G;}
      s/\n(.*)/,\1p&q/p
    ' | sed -nf - file
    

    我们可以使用perlslurp 文件,然后整个文件是一个长字符串,我们从两端烧录并在满足条件时停止。

    perl -0777 -pe '
      s/^.*\n// until /^.*abc/;    /mno/||next;
      s/.*\n$// until /mno.*$/;
    ' file
    
    • 1
  9. guest_7
    2021-09-18T05:53:47+08:002021-09-18T05:53:47+08:00

    以下是使用 sed 编辑器获得所需输出的更多方法。

    sed -n '
      /\n/{/mno/!d;P;D;}
      /abc/,$H;$!d
      z;x;G;/mno/D
      s/.//;s/.$//p
    ' file
    
    • 将文件从第一个 /abc/ 到 eof 保存在保留空间中。
    • 打印模式空间的顶部,而我们仍然可以在其中的任何位置看到 /mno/。
    • 然后剪裁图案空间的顶部并重复上一步。
    • 当 /mno/ 不再可见时停止。
    • 或者,如果没有 /mno/,则在开始此 P;D 循环之前,只需打印整个保留空间。

    另一种方法是我们只在看到 /mno/ 之前将行存储。此时我们翻转并打印保留的内容。

    sed -n '
      /abc/,$!d
      /mno/!{H;ba;}
      x;p;:a
      ${x;//P;//!p}
    ' file | sed 1d
    

    这是使用通用 itertools 模块 groupby 方法完成工作的 Python 方式。

    python3 -c 'import sys, itertools as it
    ifile,start,stop = sys.argv[1:]
    G,K,F = [],[],lambda x: x.find(stop)
    with open(ifile) as f:
      for _ in f:
        if not _.find(start): continue
        for t in it.groupby(f,F):
          G.append(list(t[1]))
          K += [t[0] > -1]
    if len(K) > 1 and not K[-1]: G.pop()
    print(*[e for L in G for e in L], sep="",end="")
    ' file "abc" "mno"
    
    • 1

相关问题

  • 重新排列字母并比较两个单词

  • 在awk中的两行之间减去相同的列

  • 多行文件洗牌

  • 如何更改字符大小写(从小到大,反之亦然)?同时[重复]

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve