需要 grep 模式旁边或下方的单词

需要 grep 模式旁边或下方的单词

我有一个文件,其中 i 包含以下几行:

    .......... FROM ABCD_EXT
    .......... FROM HEG_EXT1 
.......... from
           xyz_EXT
.......... FROM abd_EXT2 
..........where QWT_EXT.SID=POI_EXT.GET
..........where QWT_EXT.SID=POI_GET.END_EXT

我只需要 grep 那些位于“FROM”(不区分大小写)旁边或下方且以 _EXT 结尾的单词。

即,预期输出是:

ABCD_EXT 
xyz_EXT

编辑:是的,我需要 grep 'from' 之后的下一个单词,无论它出现在同一行还是下一行。

我尝试了这个,它让我正确地得到了第一部分(同一行):

grep _EXT rt.sql |grep -i from|sed -e 's/_EXT/_EXT /g'|awk '{print $NF}'|grep _EXT

从下面这一行获取单词是个问题。

答案1

pcregrep

pcregrep -Mo1 '(?<!\S)(?i:from)\s+(\S*_EXT)(?!\S)' < rt.sql
  • -M对于M多行模式
  • -o1输出sto捕获组匹配的内容。1
  • \s匹配空白字符(至少包括空格、制表符、CR 和 LF),\S匹配非空白字符。
  • x+: 匹配 1 个或多个xs
  • x*: 匹配 0 个或多个xs。
  • (?i:from): from,不区分大小写,与 相同[fF][rR][oO][mM]
  • (?<!\S):非空白的负向后查找,或 IOW前提是前面的内容不是非空白(空白或主题的开头也是如此)。
  • (?!\S):相同,但向前看而不是向后看。如果是 SQL,您可能;也希望允许(?![^\s;])

如果你没有pcregrep,你可以使用(中的perl第一个),并用 来吸食整个文件:ppcregrep-0777

perl -l -0777 -ne 'print for /(?<!\S)(?i:from)\s+(\S*EXT)(?!\S)/g' < rt.sql

或者使用 GNU,grep如果使用 PCRE 支持构建(这添加了-P使用类似 perl 的正则表达式进行匹配的选项):

grep -zPo '(?<!\S)(?i:from)\s+\K\S*EXT(?!\S)' < rt.sql | tr '\0' '\n'

由于 GNUgrep不支持-o<n>输出n第一个捕获组匹配的内容,因此我们改为-o输出匹配的全部内容,但用于\K告诉匹配器要Keep 的内容作为匹配。

由于-z我们处理的是 NUL 分隔的记录而不是行,因此假设输入不包含 NUL(通常 SQL 和文本应该是这种情况),那么这将只是一个记录,构成文件的完整内容,就像在 perl 中一样上面的 slurp 模式。不过,输出记录分隔符也将为 NUL,因此我们需要将tr它们转译为换行符,以使每个匹配项位于单独的行上。

答案2

使用GNUsed

$ sed -En 'N;s/.*from( ([^_]*_ext\>)[^\n]*\n.*|\n.* ([[:alpha:]]+_ext\>))/\2\3/Ip' input_file
ABCD_EXT
xyz_EXT

答案3

用您的示例数据尝试一下datafile

> awk -v printfirst=0 'BEGIN {IGNORECASE=1}
                       {if (printfirst == 1) {
                           print $1; printfirst=0; next
                                             }
                       } 
                       {for (i=1;i<=NF;i++) 
                           if ($i ~ /^from$/) {
                               if (i == NF) {printfirst=1} 
                               else if ($(i+1) ~ /_EXT$/) {print $(i+1)}
                           }
                       }' datafile

ABCD_EXT
xyz_EXT
> _

有几种方法可以使用awk(这里是 Awk 的 GNU 版本)来执行此操作。我选择这个是为了方便,避免两次解析输入文件。

  • -v将变量传递到 Awk 的标志。初始化变量printfirst为0,
  • BEGIN {IGNORECASE=1}使 Awk 搜索模式不区分大小写
  • 第一个{}块:有条件地打印第一个 Awk 字段,即$1并跳转到next记录
  • 第二块{}:对于解析的记录,尝试以from不区分大小写的方式匹配每个字段。
    • 如果不匹配:什么也不做。
    • 如果匹配:
      • 如果匹配字段是记录中的最后一个,则将 awk 内部变量设置printfirst为 1 并转到下一条记录
      • 如果匹配的字段不是记录中的最后一个字段,则打印记录中的下一个字段。

相关内容