【问题标题】:Multiple "grep...then..." in bashbash中的多个“grep ...然后...”
【发布时间】:2021-12-30 14:13:57
【问题描述】:

我正在编写一个 bash 脚本来监控脚本 A 的输出,并通过“grep”命令匹配关键字。如果成功找到关键字,请回显某些内容。这是我的脚本:

if script_A | grep -q 'keyword'; 
then
echo 'Found A!'

如果只有一个条件,脚本就可以正常运行。但是我找不到匹配多个关键字的方法,并使用“if...elif...else”来控制不同条件的回显内容。

这是我想要实现的逻辑:

script_A |
if grep 'keyword_A';
then echo 'Found A!'
elif grep 'keyword_B';
then echo 'Found B!'
else echo 'Found Nothing!'

谢谢!

【问题讨论】:

  • 使用awk 可能会更容易。
  • 我建议使用logger,然后使用您的系统日志管理器过滤掉输出。
  • 每个管道有一个读卡器和一个写卡器。当script_A 写入一行时,只有一个程序可以读取该行。你可以让一个程序类似于tee,或者你可以让shell将输出捕获到一个变量中,然后shell可以重复多次,但你不能让一个写有多个grep副本直接阅读。
  • 顺便说一句,script_A 的输出有多大?如果足够短,可能根本没有理由使用grep; shell 有自己的内置正则表达式和模式匹配;如果它特别大,则意味着需要内存高效的答案。

标签: bash


【解决方案1】:

如果每次写入只能有一个读者消费。然后,该读取器可以创建它读取的数据的多个副本(就像 tee 所做的那样),但最初在另一端必须只有一件事。

一种更传统的方法是让外壳成为一个阅读器,如下所示:

output=$(script_A)
if grep -q 'keyword_A' <<<"$output"; then
  echo 'Found A!'
elif grep -q 'keyword_B' <<<"$output"; then
  echo 'Found B!'
else
  echo 'Found nothing!'
do

...或者,如果您需要连续流式输出:

script_A | {
  found=0
  while IFS= read -r line; do
    if [[ $line = *keyword_A* ]]; then
      echo 'Found A!'; found=1; break
    elif [[ $line = *keyword_B* ]]; then
      echo 'Found B!'; found=1; break
    fi
  done
  if (( found == 0 )); then
    echo 'Reached end of input and found nothing!'
  fi
}

【讨论】:

  • 您好,查尔斯,感谢您的回答。但是经过测试,我发现如果输出持续生成一段时间,它就不起作用。我想要实现的是将所有输出字符串传递到下一个 if 条件。
  • 如果你想单独处理每一行,那意味着你需要一个 while read 循环。
  • 请注意,grep -q 本身在找到匹配项之前不会完成,因此解释您的原始代码以理解问题并不会让它看起来像您想要的持续的流媒体支持。 (如果您在退出 grep -q 'keyword_A' 之前不运行 grep -q 'keyword_B',这意味着您甚至在找到 A 或输入完全完成但没有找到它之后才开始搜索 B)。
  • @YuqiJin, ...无论如何,看看编辑。
  • 感谢编辑的答案。我相信它会起作用,因为我也想出了类似的解决方案并在下面回复。无论如何,感谢@Charles Duffy 的帮助!
【解决方案2】:

如果您很高兴看到grep 的输出(而不是您的自定义消息),您可以这样做:

if ! script_A | grep -e 'keyword_A' -e 'keyword_B'; then
    echo 'Found Nothing'
fi

在管道中直接操作 grep 的输出有些困难,但您可以通过以下方式获取自定义消息:

if ! script_A | grep -o -e 'keyword_A' -e 'keyword_B'; then
    echo 'Nothing'
fi | sed -e 's/^/Found /' -e 's/$/!/'

【讨论】:

    【解决方案3】:

    您可以使用 Bash 重新匹配:

    if [[ "demo_rematch" =~ [st] ]]; then
      echo "Matched from regexpr [st] is the letter ${BASH_REMATCH}!"
    fi
    

    使用单字母关键字,您可以执行类似的操作

    # grep [YES] is the same as grep [ESY]
    for regex in '[AB]' '[YES]' '[NO]'; do
      echo "$regex"
      if [[ "$(printf "keyword_%s\n" {A..G})" =~ keyword_$regex ]]; then
        echo "Found ${BASH_REMATCH/keyword_}!"
      else
        echo "Found Nothing!"
      fi
    done
    

    在现实生活中,您的关键字可能会更复杂。你仍然可以使用相同的结构,但现在我不会使用字符串“keyword_”。

    regex='(foo|bar|A|B|not me|no match|bingo)'
    echo "$regex"
    for script_A in "String with foos" "String with bar" "String with A" "String with B" "Nothing here" "Please ignore me" "and bingo"; do
      if [[ "${script_A}" =~ $regex ]]; then
        echo "Found ${BASH_REMATCH}!"
      else
        echo "Found Nothing!"
      fi
    done
    

    【讨论】:

      【解决方案4】:

      如果有人需要,我找到了可行的答案:

      #!/bin/bash
      
       function test() {
         echo "test"
        sum=0
        while true
        do
          stat_date=`date`
          echo $stat_date
        done
      }
      
      function checkcondition() {
       while read data; do
        if [[ $data == *"10:52:59"* ]]; then
        echo "Found the time!";
      
        elif [[ $data == *"hi"* ]]; then
        echo "Found hi!";
      
        else
        echo "Nothing";
      
        fi
        done;
      
      }
      
      test | checkcondition
      

      代码将不断生成时间字符串。 checkcondition 函数将接收输出。只要输出字符串包含“10:52:59”,就会打印“Found the time!”,否则打印“Nothing”。

      【讨论】:

      • 请注意,function funcname() { 以与 both POSIX sh 不兼容的方式合并了 POSIX sh 函数声明语法 (funcname() {) 和旧版 ksh​​ 函数声明语法 (function funcname {)和旧版 ksh​​。为了与现代 shell 实现最佳兼容性,我强烈推荐使用 POSIX 形式;见wiki.bash-hackers.org/scripting/obsolete
      • (另外,test 是一个内置 shell 的名称,它也是一个 POSIX 标准化的外部工具,所以最好避免重新定义它;这是拥有另一段代码的简单方法运行if test -e somefile 或类似的行为非常令人困惑)。
      猜你喜欢
      • 1970-01-01
      • 2017-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多