【问题标题】:grep/pcregrep/sed/awk the data after the last match to the end of a filegrep/pcregrep/sed/awk 最后一次匹配到文件末尾的数据
【发布时间】:2015-09-15 14:02:53
【问题描述】:

我需要在ENTRY的最后一个匹配到文件末尾之后抓取内容,我似乎无法做到。它可以是多行,数据可以包括文件末尾的任何字符,包括 (,\n, )。

我试过了:

tail -1 file # doesn’t work due to it not consistently being one line
grep "^(.*"  # only grabs one line
pcregrep -M  '\n(.*' file # I think a variation of this is the solution, but I’ve had no luck so far.  

在下面增长的文件:

TOP OF FILE                
%
ENTRY
(S®s
√6ûíπ‹ôTìßÅDPˆ¬k·Ù"=ÓxF)*†‰ú˚ÃQ´¿J‘\˜©ŒG»‡∫QÆ’<πsµ-ù±ñ∞NäAOilWçk
N+P}V<ôÒ∏≠µW*`Hß”;–GØ»14∏åR"ºã
FD‘mÍõ?*ÊÎÉC)(S®s
√6ûíπ‹ôTìßÅDPˆ¬k·Ù"=ÓxF)*†‰ú˚ÃQ´¿J‘\˜©ŒG»‡∫QÆ’<πsµ-ù±ñ∞NäAOilWçk
N+P}V<ôÒ∏≠µW*`Hß”;–GØ»14∏åR"ºã
FD‘mÍõ?*ÊÎÉC)eq  
{
DATA
}
ENTRY
(A® S\kÉflã1»Âbπ¯Ú∞⁄äπHZ@F◊§•Ã*‹¡‹…ÿPkJòÑíòú˛¶à˛¨¢v|u«Ùbó–Ö¶¢∂5ıÜ@¨•˘®@W´≥‡*`H∑”ı–Só¬<˙ìEçöf∞Gg±:œe™flflå)A®  S\kÉflã1»Âbπ¯Ú∞⁄äπHZ@F◊§•Ã*‹¡‹…ÿPkJòÑíòú˛¶à˛¨¢v|u«Ùbó–Ö¶¢∂5ıÜ@¨•˘®@W´≥‡*`H∑”ı–Só¬<˙ìEçöf∞Gg±:œe™flflå)eq  
{
DATA
}if
ENTRY
(ÌSYõ˛9°\K¬∞≈fl|”/í÷L
Ö˙h/ÜÇi"û£fi±€ÀNéÓ›bÏÿmâ[≈4J’XPü´Z
oÜlø∫…qìõ¢,ßü©cÓ{—˜e&ÚÀÓHÏÜ‚m(Œ∆⁄ˆQ˝òêpoÉÄÂ(S‘E ⁄ !ŸQ§ô6ÉH

【问题讨论】:

  • 您的文字表明您想要最后一次出现 ENTRY 之后的所有内容。您的各种命令会在以( 开头的行之后查找内容。你的偏好是什么?
  • 请注意,如问题所示,脚本中有各种形式的“弯引号”()。 Bash 不会喜欢那些。您必须使用"'
  • @John1024 到目前为止,您的回答运行良好。我真的需要(dataEOF
  • @JonathanLeffler 我相信这是我沮丧/困难的很大一部分。我没有能力更改数据。这是一个无法编辑的 ~hash。
  • 我指的是“我试过”部分的人物,你必须负责。数据不是问题(它与我碰巧使用的 telnet 会话有关,但这是我的问题)。

标签: regex bash awk sed grep


【解决方案1】:
$ awk '/^[(]/{s="";} {s=s"\n"$0;} END{print substr(s,2);}' file
(ÌSYõ˛9°\K¬∞≈fl|”/í÷L
Ö˙h/ÜÇi"û£fi±€ÀNéÓ›bÏÿmâ[≈4J’XPü´Z
oÜlø∫…qìõ¢,ßü©cÓ{—˜e&ÚÀÓHÏÜ‚m(Œ∆⁄ˆQ˝òêpoÉÄÂ(S‘E ⁄ !ŸQ§ô6ÉH

工作原理

awk 隐式地逐行遍历文件。该脚本将我们想要打印的任何内容存储在变量 s 中。

  • /^[(]/{s="";}

    每次我们找到以( 开头的行时,我们将s 设置为一个空字符串。

    这样做的目的是删除最后一次出现以( 开头的行之前的所有内容。

  • s=s"\n"$0

    我们将当前行添加到s 的末尾。

  • END{print substr(s,2);}

    到达文件末尾后,我们打印s(省略第一个字符,这将是多余的换行符)。

【讨论】:

  • 再次感谢,从昨晚开始我一直在努力解决这个问题。我很感激。
  • 如果我想打印到一个文件是不是>文件?
  • @Pumphouse 是的,只要它是不同的文件。 (您无法打印到您阅读的文件。)
  • 谢谢。我只是对你的一些东西投了赞成票,以表示感谢。
【解决方案2】:

有趣的问题。我认为您只需 sed 就可以做到这一点。当您找到匹配项时,将保留空间归零并将匹配行添加到保留空间。在最后一行,打印保留空间。

sed -n -e '/ENTRY/,$ { /ENTRY/ { h; n; }; H; $ { x; p; } }'

默认情况下不打印。从第一个条目到文件末尾:

  • 如果是入口行;将新行复制到保留空间上并继续。
  • 否则将该行附加到保留空间。
  • 如果是最后一行,则交换保持空间和模式空间,并打印模式空间(保持空间中的内容)。

如果文件的最后一行是 ENTRY 行,您可能会担心会发生什么。

给定一个data 文件:

TOP OF FILE
not wanted
ENTRY
could be wanted
ENTRY
but it wasn't
and this isn't
because
ENTRY
this is here
EOF

输出是:

ENTRY
this is here
EOF

如果不想ENTRY出现,稍微修改一下脚本:

sed -n -e '/ENTRY/,$ { /ENTRY/ { s/.*//; h; n; }; H; $ { x; s/^\n//; p; } }'

【讨论】:

    【解决方案3】:

    使用tac 你可以做到:

    tac <file> | sed -e '/ENTRY/,$d' | tac
    

    这将打印文件的行颠倒,然后使用sed 删除从现在第一次出现 ENTRY 到文件现在结尾的所有内容,然后再次反转行以获得原始顺序。

    正如 Jonathan Leffler 指出的那样,一种更快的方法可以做到这一点——尽管可能不多,因为 tac 仍然有很多工作要做,而且它需要 3 个进程而不是一个进程的所有开销,但是 sed可以更有效地完成,但只是在我们找到 ENTRY 行时结束,而不是处理文件的其余部分以删除这些行:

    tac <file> | sed -e '/ENTRY/q' | tac
    

    尽管他的回答通常会更好。该答案将包括 ENTRY 行。如果你不想这样做,你也可以这样做

    tac <file> | sed -n '/ENTRY/q;p' | tac
    

    默认不打印任何输出,然后在找到 ENTRY 行后立即退出,但使用 p 命令打印这些行,直到到达该行。

    【讨论】:

    • 这是一个简单而有效的解决方案,但使用三个过程就足够了。
    • @JonathanLeffler 很公平,但在我看到您的解决方案之前,我不知道如何使用它!我将不得不解决你的问题,但我已经支持从目前提供的三个答案中选择这个答案
    • 如果您需要立即完成它,并且文件不是巨大的(不大于 MiB),那么它可能比花时间研究如何避免多个进程更有效。如果你有一个巨大的文件,你可以使用sed -e '/ENTRY/q',这样你就可以在第一行停止处理。但是之前的tac 可能还有很多工作要做,特别是如果它的输入来自管道或其他不可搜索的东西。
    【解决方案4】:

    这也应该有效(至少对于 gawk)

    awk -vRS="ENTRY" 'END{print $0}'
    

    将记录分隔符设置为您的模式并打印最后一条记录。

    【讨论】:

      【解决方案5】:

      在内存中加载文件

       sed -e 'H;$!d' -e 'x;s/.*ENTRY[[:blank:]]*\n//' YourFile
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-10-13
        • 1970-01-01
        • 2020-08-24
        • 1970-01-01
        相关资源
        最近更新 更多