如何检查文件中是否匹配所有字符串

时间:2018-05-07 11:40:51

标签: bash awk grep

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

$ 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并存储返回代码,然后检查它是否为grater,然后是0。

7 个答案:

答案 0 :(得分:2)

这是检查的功能

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

答案 1 :(得分:1)

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

答案 2 :(得分:1)

#!/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问题,其中应该检查文件列表并且可以缩短一点,因为文件名不需要一次又一次地传递给函数。

#!/斌/庆典

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

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

答案 3 :(得分:1)

您可以使用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中找到的唯一模式的数量。

答案 4 :(得分:1)

当节点作为文件中的第一列提供时,您可以使用grep 我想使用您的tr方法,用不同的方式编写。

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

您可以使输出看起来像具有进程替换的文件

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

如果要使用文件的第一个字段检查这些字段,请剪切文件。

cut -d' ' -f1 file

您可以将outoput用于其他流程替代并使用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/'

答案 5 :(得分:1)

另一个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

你可以对输出大小进行调整以使其失败或成功,但也许不会忽略丢失的内容也是有用的。

答案 6 :(得分:0)

使用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 $(...)