在具有多个 grep 命令的 IF 中使用 NOT 运算符

Using NOT operator in an IF with multiple grep commands

我是 Shell 脚本的新手,正在编写 Korn shell 脚本。

我的目标是在 4 个单独的文件中搜索 fileA.txt 中的每一行(我们称它们为 fileA.txtfileB.txtfileC.txtfileD.txt ).我需要为 fileA.txt 中的行打印 "not found",这些行在单独的文件中的四个文件中均未找到。

所以我想出了下面的 If 语句。我正在尝试使用 && 组合 4 个 grep 命令,并执行逻辑 Not (!) 因为我只需要在这 4 个文件中都找不到的行。

for i in $(<fileA.txt);
do
    if !((grep -q $i fileB.txt) && (grep -q $i fileB.txt) && (grep -q $i fileC.txt) && (grep -q $i fileD.txt)); then
        print "$i not found in either of 4 files"
    fi
done

我知道语法肯定有问题,但作为 shell 脚本的初学者,我搞不懂。

您不需要括号。事实上,因为您使用的是 &&,所以不需要对 grep.

进行 3 次单独调用
while IFS= read -r line; do
  if ! grep -q "$i" fileB.txt fileC.txt fileD.txt; then
    print "$i not found in any of the 3 files"
  fi
done < fileA.txt  

你甚至不需要循环;此模式包含在 -f 选项中:

if ! grep -f fileA.txt fileB.txt fileC.txt fileD.txt; then
   ...
fi

它没有回答您提出的问题,因此违反了 SO 政策,但是有一种方法可以一次性解决您使用 awk 的实际问题,我无法在合理的评论中给出:

 awk 'FNR==NR{a[[=10=]];next} {for(p in a)if([=10=]~p){delete a[p]}} \
   END{for(p in a)print "notfound: ",p}' patternfile data1 data2 data3 etc

notfound:只是为了清楚起见,您可以根据需要更改或省略它。

输出值(未在任何数据文件中找到的模式)不一定与模式文件中的顺序相同;如果你关心这个:

 awk 'FNR==NR{a[[=11=]]=FNR;next} {for(p in a)if([=11=]~p){delete a[p]}} \
   END{for(p in a)print a[p],p}' patternfile data1 data2 data3 etc | sort -k1n | cut -f2-
 # or in GNU awk v4+ only
 awk 'FNR==NR{a[[=11=]]=FNR;next} {for(p in a)if([=11=]~p){delete a[p]}} \
   END{PROCINFO["sorted_in"]="@val_num_asc";for(p in a)print p}' patternfile data1 data2 data3 etc 

你的问题也含糊不清'lines';您是说 patternfile 中的每一行都应该 作为一个数据文件中的一行 出现,还是它可以出现在一行中但不一定是整行?此外,模式文件中的值是仅数据字符还是其中任何一个与数据中的不同内容匹配的特殊字符?例如,您发布时使用 grep 默认值( awk 以及我上面的 ~ )如果 patternfile 包含一行 boojum.. 该项目将是如果数据文件包含以下任何行,则视为已找到:

 boojum..
 boojumXY
 the snark was a boojum!!

OTOH 模式文件行 ^abc 将匹配:

 abc
 abcdefghi

但不会匹配:

 ^abc

您可以在 grep 中使用选项 -x 获得全行匹配,使用 -F 进行文字(非正则表达式)匹配,或两者兼而有之。这些也可以在 awk 中实现,但有所不同。