【问题标题】:egrep in shell scriptingshell脚本中的egrep
【发布时间】:2020-10-05 18:22:15
【问题描述】:

任何人都可以在这里提供帮助。如果 egrep 不可行,其他建议也将受到高度赞赏。

当它位于“UTL_RECOMP_SLAVE_75”字符串的下一行时,我正在尝试使用“UTL_RECOMP_SLAVE_75”将 egrep 表达式写入 grep ORA-00942。然而,文件中任何其他行中的 ORA-00942 应被忽略。仅当 ORA-00942 在下一行中后跟“UTL_RECOMP_SLAVE_75”时,才需要对其进行 grep。

ORA-12012: error on auto execute of job "SYS"."UTL_RECOMP_SLAVE_75"
ORA-00942:     <<<<<<<<<<<<<<<<<< should be grepped along with "UTL_RECOMP_SLAVE_75"

ORA-00490: error text is xyz
ORA-00942:   <<<<<<<<<<<<<<<< this should be ignored

【问题讨论】:

  • 我知道sed在这类任务上比较好,你调查过吗?
  • 谢谢亚龙。不,我对 shell 脚本很陌生。您对此有 sed 表达式的任何想法吗?
  • sed 和 grep 都是错误的工具,不能用于涉及搜索多行输入的任何事情。只需使用 awk(或者如果您不介意非标准工具,可以使用 perl、ruby、python 等)
  • @Ed Morton:有一个使用 grep 的自然解决方案正在运行:grep -A1 UTL_RECOMP_SLAVE_75 inputfile | grep -B1 ORA-00942
  • @LászlóSzilágyi 这不是 grep 的自然解决方案,它是具有 2 个 grep 和一个 shell 管道的解决方案,当 ORA-00942 出现在与 UTL_RECOMP_SLAVE_75 相同的行。

标签: shell scripting grep


【解决方案1】:

这是一个 Perl 解决方案。它不像 sed 答案那么短,但我觉得它更具可读性:

perl -nle 'print if (/^ORA-00942/ && $wanted); if (/UTL_RECOMP_SLAVE_75/) {$wanted=1} else {$wanted=0}' /your/file

或稍短的版本:

perl -nle 'print if (/^ORA-00942/ && $wanted); $wanted=(/UTL_RECOMP_SLAVE_75/ ? 1 : 0)' /your/file

如果当前行包含“UTL_RECOMP_SLAVE_75”,这会将 $wanted 标志设置为 true,否则设置为 false。

这仅打印以“ORA-00942”开头的行,并且仅在 $wanted 为真时打印。

如果您还想打印上一行,请改用Ed Morton's solution,它会同时打印两者。

【讨论】:

    【解决方案2】:

    这是一个简单的 grep 解决方案。

    grep -A1 UTL_RECOMP_SLAVE_75 inputfile | grep -B1 ORA-00942
    

    你可以用两个 grep 来完成。因为 grep 有一个好用的 选项-An-Bn

    例如: grep UTL_RECOMP_SLAVE_75 -A3 inputfile

    在匹配行之后打印 3 行尾随上下文 -Bn 选项是: 在匹配行之前打印 n 行前导上下文。
    请阅读man grep

    在这个答案中,我将第一个 grep 传递到了第二个。但是你可以 也可以分两步使用 tmp_file 而不是管道来查看 grep 命令的工作原理。

    grep -A1 UTL_RECOMP_SLAVE_75 inputfile >tmp_file
    grep -B1 ORA-00942 tmp_file
    

    如果需要,您可以更精确地进行匹配。 例如:

    grep -A1 -w UTL_RECOMP_SLAVE_75 inputfile | grep -B1 -w ^ORA-00942
    

    【讨论】:

    • 这不是在寻找ORA-00942 has to be grepped only when its in the next line followed by "UTL_RECOMP_SLAVE_75",因此当ORA-00942UTL_RECOMP_SLAVE_75 出现在同一行 时会失败(即在不应该的时候产生输出)。试试echo 'ORA-00942 foo UTL_RECOMP_SLAVE_75' | grep -A1 UTL_RECOMP_SLAVE_75 | grep -B1 ORA-00942
    【解决方案3】:

    这将在每个 UNIX 机器上的任何 shell 中使用任何 awk 来完成您想要的操作:

    $ awk '/ORA-00942/ && (p ~ /UTL_RECOMP_SLAVE_75/){print p ORS $0} {p=$0}' file
    ORA-12012: error on auto execute of job "SYS"."UTL_RECOMP_SLAVE_75"
    ORA-00942:     <<<<<<<<<<<<<<<<<< should be grepped along with "UTL_RECOMP_SLAVE_75"
    

    【讨论】:

      【解决方案4】:

      使用 sed:

      sed -n '/"UTL_RECOMP_SLAVE_75"/{N;/\n.*ORA-00942/p;D}'
      

      【讨论】:

      • 您应该提及哪个 sed 版本将与该表达式一起使用。使用 OSX/BSD sed 失败,sed: 1: "/"UTL_RECOMP_SLAVE_75"/ ...": extra characters at the end of D command
      【解决方案5】:

      我建议grepawk 的组合:

      您可以使用grep -n 来获取包含“ORA-00942”的行,您会得到如下内容:

      2:line_2 contains ORA-00942
      8:line_5 contains ORA-00942
      

      由此,使用 awk 和 ':' 作为字段分隔符,您可以获得包含“ORA-00942”([2,8])的行号。

      然后您可以使用grep -n 对包含“UTL_RECOMP_SLAVE_75”的行进行排序,可能类似于:

      4:line_4 contains UTL_RECOMP_SLAVE_75
      7:line_7 contains UTL_RECOMP_SLAVE_75
      

      再次使用awk,您将获得包含“UTL_RECOMP_SLAVE_75”([4,7])的行号。

      从那里您可以处理两个行号列表以获得匹配的行号。

      提示和技巧:不要保留包含“UTL_RECOMP_SLAVE_75”的行,而是将行号加一(而不是 [4,7] 你有 [5,8]),它可能更容易找到两个具有相同数字的列表,而不是检查“加一”值。

      【讨论】:

      • 在使用 awk 时永远不需要 grep。
      猜你喜欢
      • 2010-12-14
      • 2013-06-03
      • 2019-02-24
      • 1970-01-01
      • 2018-05-19
      • 2021-11-11
      • 2011-05-21
      • 1970-01-01
      • 2013-02-10
      相关资源
      最近更新 更多