将命令行参数作为搜索模式传递​​给 grep 并打印与它们全部匹配的行

Pass command-line arguments to grep as search patterns and print lines which match them all

我正在学习 grep 命令。 我想制作一个程序,当用户输入多个单词时,输出包含数据文件中单词的一行。 所以我将用户输入的单词与“|”连接起来并将它们放在 grep 命令中以创建我想要的程序。 但这是 OR 操作。我想做AND运算。

所以我学会了如何使用 grep 命令进行 AND 操作,如下所示。

cat <file> | grep 'pattern1' | grep 'pattern2' | grep 'pattern3'

但我不知道如何将用户输入放在'pattern1'、'pattern2'、'pattern3'位置。因为用户输入的字数是不确定的。 随着用户输入的增加,grep 必须使用越来越多的管道执行,但我不知道如何构建这部分。

用户输入如下:

$ [the name of my program] 'pattern1' 'pattern2' 'pattern3' ...

非常感谢你的帮助。

原则上,您所要求的可以通过输出到临时文件的循环来完成。

file=inputfile
temp=$(mktemp -d -t multigrep.XXXXXXXXX) || exit
trap 'rm -rf "$temp"' ERR EXIT
for regex in "$@"; do
    grep "$regex" "$file" >"$temp"/output
    mv "$temp"/output "$temp"/input
    file="$temp"/input
done
cat "$temp"/input

但是,更好的解决方案可能是安排 Awk 一次检查所有模式,避免一遍又一遍地读取相同的行。

将参数原封不动地传递给 Awk 并非易事。在这里,我们只是将它们作为 command-line 参数传递,并将它们处理成 Awk 脚本本身内的数组。

awk 'BEGIN { for(i=1; i<ARGC; ++i) a[i]=ARGV[i];
        ARGV[1]="-"; ARGC=1 }
{ for(n=1; n<=i; ++n) if ([=11=] !~ a[n]) next; }1' "$@" <file

简而言之,在 BEGIN 块中,我们将 command-line 参数从 ARGV 复制到 a,然后替换 ARGVARGC 向 Awk 传递一个新的(明显的)command-line 参数数组,其中仅包含 -,这意味着读取标准输入。然后,如果来自标准输入的当前输入行不匹配,我们简单地遍历 a 并跳到下一行。任何剩余的行都匹配了我们传入的所有模式,因此被打印出来。

建议使用awk模式逻辑:

 awk '/RegExp-pattern-1/ && /RegExp-pattern-2/ && /RegExp-pattern-3/ 1' input.txt

优点:您可以在 RegExp 模式上使用逻辑运算符 && ||。你正在扫描整个文件一次。

缺点:必须提供文件列表(不能遍历子目录),与grep -Egrep -P

相比,RegExp语法有限

使用 grep -f 您可以 grep 多个项目,当每个项目都在文件中的一行时。

<(command)可以让Bash认为command的结果是一个文件

使用 printf "%s\n" 和参数列表,每个参数都打印在一个新行上。

在一起:

grep -f <(printf "%s\n" "$@") datafile