【问题标题】:How to check if all the strings matching in a file如何检查文件中的所有字符串是否匹配
【发布时间】:2018-05-08 18:57:33
【问题描述】:

我正在从现有程序中获取输入,该程序由由管道 (|) 字符分隔的字符串组成:

$ echo "$list_of_nodes"
NODE-BB-4|NODE-AA-1|DUMMY

现在我需要检查它们中的每一个是否存在于单独的文件中:

$ cat file
NODE-BB-4 1.1.1.1
NODE-AA-1 2.2.2.2
  • 案例 1

    当输入字符串为"NODE-BB-4|NODE-AA-1"时应该通过,因为它们都存在于文件中,

  • 案例 2

    当输入字符串为"NODE-BB-4|NODE-AA-1|DUMMY" 时,应该会失败,因为文件中不存在"DUMMY"

这就是我的想法,但似乎绝对不是最好的主意:

$ echo "$list_of_nodes" |tr '|' '\n' |while read line;
> do grep -q "$line" foo ;
> echo $? ;
> done|awk '{s=s+$0} END{print s}' |awk '$1>0{print "Fail"}'
Fail

在这里,我循环每个模式以 grep 并存储返回码,然后检查它是否大于 0。

【问题讨论】:

    标签: bash awk grep


    【解决方案1】:

    这是这种检查的功能

    check() {
       FileToCheck="$1"
    
       #cycle will check all patterns.
       #if one of patterns will fail, function will stop immediately with Return Code 1
       while read p; do
         grep "${p}" ${FileToCheck} >/dev/null || { echo "${p} not found in ${FileToCheck}"; return 1; }
       done < <( tr '|' '\n' )  #modify input for cycle via tr(replace | by newlines)
       #if we running here, all checks are Okay, Return Code 0.
       return 0
    }
    

    示例文件:

    $ cat patterns 
    NODE-BB-4|NODE-AA-1|DUMMY
    
    $ cat file
    NODE-BB-4 1.1.1.1
    NODE-AA-1 2.2.2.2
    

    这是一个使用示例:

    cat patterns | check file
    echo $?
    

    结果:

    DUMMY not found in file
    1
    

    【讨论】:

      【解决方案2】:

      Awk解决方案:

      list_of_nodes="NODE-BB-4|NODE-AA-1|DUMMY"
      awk -v nodes_str="$list_of_nodes" \
      'BEGIN{ len = split(nodes_str, arr, "|") }{ nodes[$1] }
       END{ for (i=1; i<=len; i++) if (!(arr[i] in nodes)) print "Fail" }' file
      

      【讨论】:

        【解决方案3】:
        #!/bin/bash
        
        file="$1"
        p="NODE-BB-4|NODE-AA-1|DUMMY"
        patterns=${p//|/ }
        
        fileMatchesAllNames () {
          file=$1
          if [[ $# -eq 1 ]]
          then
            echo "$file"
          else
            shift
            pattern=$1
            shift
            grep -q "$pattern" "$file" && fileMatchesAllNames "$file" $@
          fi
        }
        
        test -f "$file" && fileMatchesAllNames "$file" $patterns
        

        调用函数时会使用一堆要搜索的模式,只要有一个,就会获取第一个,测试它并使用shift 将其删除以进行下一次调用。

        grep -q 会在找到匹配项后立即返回(隐含 -m1)。

        如果文件匹配所有模式,则打印其名称。否则,一旦模式无法匹配,程序就会静默终止。

        它从以前的解决方案修改为 SO 问题,其中应该检查文件列表并且可以缩短一点,因为文件名不需要一次又一次地传递给函数。

        #!/bin/bash

        file="$1"
        p="NODE-BB-4|NODE-AA-1|DUMMY"
        patterns=${p//|/ }
        
        fileMatchesAllNames () {
          if [[ $# -eq 0 ]]
          then
            echo "$file"
          else
            pattern=$1
            shift
            grep -q "$pattern" "$file" && fileMatchesAllNames $@
          fi
        }
        
        test -f "$file" && fileMatchesAllNames $patterns
        

        请注意,模式不允许包含空格,以便脚本正常工作。

        【讨论】:

          【解决方案4】:

          您可以使用 bash 脚本:

          #!/usr/bin/env bash                                                                           
          
          pattern="NODE-BB-4\|NODE-AA-1\|DUMMY"
          words=3  # Number of patterns in $pattern
          if (($(grep -o "$pattern" inputfile.txt | sort -u | wc -l) < $words)); then                                  
              echo "FAIL: Not all patterns found in input file"                                                                                
          else                                                                                          
              echo "SUCCESS: All patterns found in input file"                                                                             
          fi
          

          这使用管道命令:

          grep -o "NODE-BB-4\|NODE-AA-1\|DUMMY" inputfile.txt | sort -u | wc -l
          

          这将返回在inputfile.txt 中找到的唯一模式的数量。

          【讨论】:

            【解决方案5】:

            当节点作为文件的第一列给出时,您可以使用grep
            我想使用你的tr 方法,写法不同。

            tr '|' '\n' <<< "${list_of_nodes}"
            

            您可以使用进程替换使输出看起来像一个文件

            <(tr '|' '\n' <<< "${list_of_nodes}"
            

            当您想用文件的第一个字段检查这些时,请剪切文件。

            cut -d' ' -f1 file
            

            您可以将输出用于另一个进程替换并使用grep(选项 x:完全匹配)。

            grep -xvf <(cut -d' ' -f1 file) <(tr '|' '\n' <<< "${list_of_nodes}")
            

            现在您可以将输出替换为sed

            sed -r 's/.+/FAIL: &/'
            

            零件在一起:

            grep -xvf <(cut -d' ' -f1 file) <(tr '|' '\n' <<< "${list_of_nodes}") |
               sed 's/.+/FAIL/'
            

            【讨论】:

              【解决方案6】:

              另一个awk

              $ awk 'NR==1 {n=split($0,x,"|"); 
                            for(i=1;i<=n;i++) nodes[x[i]]; 
                            next} 
               $1 in nodes {delete nodes[$1]} 
                       END {for(k in nodes) print "fail: " k}'  <(echo "$list_of_nodes") file
              
              fail: DUMMY
              

              删除所有看到的节点并打印带有失败标签的剩余节点。

              或者,另一种比较和输出缺失节点的快速方法

              $ comm -23 <(tr '|' '\n' <<< "$list_of_nodes" | sort) <(cut -d' ' -f1 file | sort)
              DUMMY
              

              您可以根据输出大小设置失败或成功,但也许不忽略缺少的内容也很有用。

              【讨论】:

                【解决方案7】:

                使用 sed

                list_of_nodes='NODE-BB-4|NODE-AA-1|DUMMY'
                sed $(echo "$list_of_nodes" | \
                sed "s/|/\/!bA;\//g;s/^/ :B;\$bC;N;bB;:C;\//;s/$/\/!bA;d;:A;s\/.*\/fail\/ file/")
                

                首先用 sed 从 list_of_nodes 创建一个 sed 命令

                :B;$bC;N;bB;:C;/NODE-BB-4/!bA;/NODE-AA-1/!bA;/DUMMY/!bA;d;:A;s/.*/fail/ file
                

                然后执行

                sed $(...)
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2010-12-08
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-09-17
                  • 2012-10-04
                  相关资源
                  最近更新 更多