【问题标题】:Display match found or not using awk使用 awk 找到或未找到显示匹配项
【发布时间】:2020-09-05 06:06:26
【问题描述】:

我有一个场景 我在一个名为 demo.txt 的文件中有三个单词

我的三个字是:苹果、芒果、葡萄

我想编写一个线性命令来检查文件中是否所有三个单词都存在,然后显示成功找到匹配项,否则显示未找到匹配项

如何以一种线性方式使用 awk 命令

下面是我的代码不工作

awk '{print (/apple/|/mango/|/grapes/ ? "true : match found " : "false : not found ")}' /D/demo.txt

示例文件:demo.txt

abc:apple
b:mango
fgg:grapes
ball , candle 
vik,mani
raj,vilas

除了第一个文件**我还有第二个文件,其中包含以下文本

Azr
hjkds
$$ABC=%wkde**mo
$Bilas=%ram 
xyz
vxbnx
ram 

我想检查是否存在确切的关键字 $$ABC=%wkde**mo $比拉斯=%ram

如果找到匹配显示消息关键字找到或否则显示关键字未找到

【问题讨论】:

  • You really need awk? grep -E "apple|mango|grapes" 080_sin080a.txt && echo "found" || echo "not found"?
  • @PabloA 检查是否存在三个单词中的任何一个,而 OP 询问输入是否包含所有三个单词
  • 请提供示例文件以供测试。部分匹配就足够了,即。 葡萄 ~ 葡萄籽?
  • 您得到了几个答案,请参阅stackoverflow.com/help/someone-answers 了解下一步该做什么。

标签: linux shell awk


【解决方案1】:

请您尝试以下操作。如果您的 awk 支持单词边界。

awk '
/\<apple\>/{
  app_found=1
}
/\<mango\>/{
  mango_found=1
}
/\<grapes\>/{
  grapes_found=1
}
END{
  if(app_found && mango_found && grapes_found){
    print "All 3 words found."
  }
  else{
    print "All 3 words are NOT present in whole Input_file."
  }
}
' Input_file

【讨论】:

  • 我已经发布了有关问题的示例文件,请检查
  • @rarkatatruenayu,好的,请立即检查我编辑的解决方案并告诉我?
  • @RavinderSingh13 一切都很好。我误解了这个问题。我认为 OP 希望“行”包含三个单词。
  • @RavinderSingh13 代码正如预期的那样完美......它可以像传递多个关键字(如 |apple|mango|grapes ......该代码适用于 3 个关键字,假设如果我需要检查 10 个关键字,那么代码需要更改它们是没有可重用性的......总是需要手动更改代码
  • @RavinderSingh13 如果找到关键字,即使代码不输出值,请以这样的方式编写代码,如果我添加多个关键字,它可以重复使用你能帮我写代码吗?提供更好的解决方案
【解决方案2】:

已编辑答案:以下命令已使用上面提供的输入示例进行了测试,并且可以正常工作:

awk '
  BEGIN { RS = "§" }
  {print (/apple/ && /mango/&&/grapes/) ? "match found" : "match not found"}
' demo.txt

我使用 char § 作为记录分隔符,因为输入中没有这样的 char 并且因为 RS = "\0" 不可移植。如果您觉得输入文件中可能会出现这样的§,您可以使用以下便携式解决方案:

awk '
  { i = i $0 } 
  END { print (i ~ /apple/ && i ~ /mango/ && i ~ /grapes/) ? "match found" : "match not found"}
' demo.txt

【讨论】:

  • @Sundeep:如果 OP 真的想跨行匹配,我无法从他的 awk sn-p 推断出,他可以将记录分隔符 RS 更改为 \n 以外的其他内容.
  • @Sundeep:你是对的,我学到了一些新东西。我将RS = "" 更改为RS="\0",这似乎有效,即使有几个段落。
  • @Sundeep:RS="\0" 的构造似乎不可移植。我将输入另一个未出现在输入中的字符,如 v.gr。 §.
  • 不要选择一些你希望不会出现在输入中的随机字符,只需使用便携式解决方案(选择一个比常用的i更好的名称,例如rec,作为记录)。不过,创建记录应该是 { rec = (NR&gt;1 ? rec ORS : "") $0 },而不仅仅是 { rec = rec $0 },因为后者中输入行之间的直接连接将创建未出现在输入中的字符串。
  • 要了解我对串联的含义,请尝试将big man 添加为一个输入行,然后在下一行添加go fish,然后搜索mango - 它会匹配,因为@987654339 @ 将创建 big mango fish(这听起来很美味,但在餐厅环境之外可能不受欢迎:-))。
【解决方案3】:

使用 GNU awk 进行多字符 RS:

awk -v RS='^$' '
    { f = (/apple/ && /mango/ && /grapes/) }
    END { print (f ? "true : match found " : "false : not found "); exit !f }
' /D/demo.txt

或者如果您不想接受部分匹配,则添加单词边界:

awk -v RS='^$' '
    { f = (/\<apple\>/ && /\<mango\>/ && /\<grapes\>/) }
    END { print (f ? "true : match found " : "false : not found "); exit !f }
' /D/demo.txt

您需要在END 部分中进行打印,而不是在处理输入以正确处理空文件时,exit 确保您在匹配成功时设置成功退出状态时的行为与 grep 相同,否则失败。

你可以使用任何 awk:

awk '
    { rec = rec $0 ORS }
    END {
        $0 = ORS rec
        f = (/[^[:alnum:]_]apple[^[:alnum:]_]/ && /[^[:alnum:]_]mango[^[:alnum:]_]/ && /[^[:alnum:]_]grapes[^[:alnum:]_]/)
        print (f ? "true : match found " : "false : not found ")
        exit !f
    }
' /D/demo.txt

或者如果您不想一次将整个文件读入内存,那么也可以使用任何 awk:

awk '
    BEGIN { numTgts = split("apple mango pears",words) }
    {
        for (i in words) {
            word = words[i]
            if ( (FS $0 FS) ~ ("[^[:alnum:]_]" word "[^[:alnum:]_]") ) {
                if ( ++numHits == numTgts ) {
                    f = 1
                    exit
                }
                delete words[i]
            }
        }
    }
    END {
        print (f ? "true : match found " : "false : not found ")
        exit !f
    }
' /D/demo.txt

或用于字符串而不是正则表达式比较(以上所有内容都使用):

awk '
    BEGIN {
        numTgts = split("apple mango pears",tmp)
        for (i in tmp) {
            words[tmp[i]]
        }
        FS = "[^[:alnum:]_]+"
    }
    {
        for (i=1; i<=NF; i++) {
            word = $i
            if (word in words) {
                if ( ++numHits == numTgts ) {
                    f = 1
                    exit
                }
                delete words[word]
            }
        }
    }
    END {
        print (f ? "true : match found " : "false : not found ")
        exit !f
    }
' /D/demo.txt

【讨论】:

    【解决方案4】:

    另一个从demo 文件中读取单词,将它们散列到a 散列中,计算匹配项,如果任何匹配单词没有匹配项,prints false

    $ awk 'NR==FNR {           # read and process demo
        split($0,t,/ *, */)    # split by comma and spaces, if any to a temp array
        for(i in t)            # make another array with match words as keys
            a[t[i]]
        next
    }
    {
        for(i=1;i<=NF;i++)     # iterate all space separated words in the file
            if($i in a)
                a[$i]++        # count match words in  it
    }
    END {                      # in the end
        for(i in a)
            if(!a[i]) {        # if there was a match word that had no matches
                print "false"  # print false
                exit           # and exit
            }
        print "true"           # else all match words matched in the file
    }' demo file
    

    输出是truefalse

    更新:在您的示例文件中,匹配词被发现附加到其他字符串的冒号,解决方案本身不会匹配。您需要将上面的主循环修改为:

    {
        n=split($0,t,/[^a-zA-Z]+/) # split by all non-alphabetical chars
        for(i=1;i<=n;i++)          # iterate all words in the array t
            if(t[i] in a)
                a[t[i]]++          # count match words in it
    }
    

    它将按所有非字母字符 ([^a-zA-Z]) 分割行,并将这些子字符串视为单词。修改该正则表达式以满足您的需求。

    【讨论】:

      【解决方案5】:

      Perl 很方便

      $ perl -0777 -ne  ' if( /apple/ && /mango/ && /grapes/ ) { print "Found\n" } else { print "not found\n" }  ' demo.txt
      Found
      $ 
      

      【讨论】:

        猜你喜欢
        • 2019-12-19
        • 1970-01-01
        • 2015-05-17
        • 2022-08-18
        • 2020-12-28
        • 1970-01-01
        • 1970-01-01
        • 2016-12-28
        • 2020-09-27
        相关资源
        最近更新 更多