【问题标题】:get the last word in body of text获取正文中的最后一个单词
【发布时间】:2015-09-08 11:08:46
【问题描述】:

考虑到一个文本体可以跨越不同数量的行,我需要使用 解决方案在多个文件中搜索相同的模式并获取最后一个单词身体。

一个文件可以包含这样的格式,我想要的单词可以命名为任何格式

call function1(input1,  
               input2,    #comment  
               input3)    #comment  
               returning randomname1,    
             randomname2,  
                 success3

call function1(input1,
               input2,    
               input3)    
               returning randomname3, 
randomname2, 
randomname3


call function1(input1,
               input2,    
               input3)   
               returning anothername3, 
randomname2, anothername3

我需要将结果打印为

成功3
随机名称3
别名3

我还需要一些关于每个的文件名和行信息。

我试过了

pcregrep -M 'function1.*(\s*.*){6}(\w+)$' filename.txt

这太贪心了,我仍然需要打印出特定的分组值而不是整个模式。我的示例代码中的单词function1 和返回将始终命名为this,并且可以在我的表达式中进行硬编码。

【问题讨论】:

  • 这些代码块是同一个文件的一部分吗? IE。您要打印“段落”的最后一个单词还是文件的最后一个单词?
  • 是的,代码块是同一个文件的一部分。我想要每一段的最后一个词。
  • 我没有意识到我的问题丢失了一些格式,所以我需要澄清一下。使用 'returning' 的行,例如返回 randomname1、randomname2、success3' 可以是一行或 3 行。此外,我的函数将始终命名为 function1,否则我将编辑名称,因此我希望我的搜索模式包含此名称。
  • 如果一个“段落”不包含function1,你什么都不想要打印?
  • 是的,正确,只有那些段落。

标签: grep sed awk regex awk sed grep


【解决方案1】:

下面的awk解决方案怎么样:

awk 'NF == 0 {if(last) print last; last=""} NF > 0 {last=$NF} END {print last}' file

$NF 正在获取最后一个“单词”的值,其中NF 代表字段数。然后last 变量总是将最后一个单词存储在一行中,如果遇到空行则打印它,表示段落的结尾。

匹配function1条件的新版本。

awk 'NF == 0 {if(last && hasF) print last; last=hasF=""}
  NF > 0 {last=$NF; if(/function1/)hasF=1}
  END {if(hasF) print last}' filename.txt

【讨论】:

  • 很好的答案,但您可以简单地使用if (last) 而不是if (length(last) > 0)
  • if (last) 如果 last 包含看起来像数字的文本并且数值计算为零,则将失败。请改用if (last!=""),因为您正在使用last="" 重置它。
【解决方案2】:

代码块的最后一句话

使用 的记录分隔符RS 将文件分割成块。一条记录将被定义为一个文本块,记录由双换行符分隔。

一条记录由多个字段组成,每两个连续字段由空格或单个换行符分隔。

现在我们要做的就是打印每条记录的最后一个字段,生成以下代码:

awk 'BEGIN{ FS="[\n\t ]"; RS="\n\n"} { print $NF }' file

解释:

  • FS 这是字段分隔符,设置为换行符、制表符或空格:[\n\t ]
  • RS 这是记录分隔符,设置为双换行符:\n\n
  • print $NF 这将打印带有索引NF 的字段$,这是一个包含字段数的变量。因此,这会打印最后一个字段。

注意:要捕获文件应以双换行符结尾的所有段落,这可以通过使用 $ echo -e '\n\n' >> file 预处理文件轻松实现。

基于 cmets 的替代解决方案

一个更优雅简单的解决方案如下:

awk -v RS='' '{ print $NF }' file

【讨论】:

  • 它确实返回了预期的输出。我使用RS = "" 尝试过类似的操作,但它没有返回第一段。有点奇怪。
  • 在这里工作得很好,我会把它添加到答案中。
  • @Birei 我怀疑您在读取第一条记录后设置 RS,例如awk '{RS=""; print}' 而不是 awk 'BEGIN{RS=""} {print}awk -v RS= '{print}'。如果这不是问题,请发布您的脚本,我们可以帮助您调试它。
  • @Birei 你的输入文件有问题。也许那里有一些控制字符,或者“第二段”实际上由空白字符分隔,但“第一段”末尾没有换行符,看起来就像是屏幕上的换行符。试试cat -v -n file 看看一切。
  • @EdMorton:是的。就是这样。我有空白字符。谢谢楼主。
【解决方案3】:

这是shellfish的awk解决方案的perl版本(加上关键字):

perl -00 -nE '/function1/ and /returning/ and say ((split)[-1])' file

或者,使用一个正则表达式:

perl -00 -nE '/^(?=.*function1)(?=.*returning).*?(\S+)\s*$/s and say $1' file

但关键是 -00 选项,它一次读取文件一个段落。

【讨论】:

  • 这个问题和任何带有RS="" 的 awk 解决方案的一个失败是它不能计算“行”,它现在计算“段落”:你不能得到行号,只有“记录”号。
【解决方案4】:

这将从您发布的输入文件中生成您显示的输出:

$ awk -v RS= '{print $NF}' file
success3
randomname3
anothername3

如果你想像你提到的那样打印 FILENAME 和行号,那么这可能就是你想要的:

$ cat tst.awk
NF { nr=NR; last=$NF; next }
{ prt() }
END { prt() }
function prt() { if (nr) print FILENAME, nr, last; nr=0 }

$ awk -f tst.awk file
file 6 success3
file 13 randomname3
file 20 anothername3

如果这不能满足您的要求,请编辑您的问题,以提供更清晰、更具代表性和准确的样本输入和预期输出。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-29
    • 2013-11-25
    • 2013-09-07
    • 1970-01-01
    • 2011-08-12
    • 2012-07-19
    • 1970-01-01
    相关资源
    最近更新 更多