我想要 grep 包含模式 A (iwant) 的文件,但我想排除包含模式 B (idonwant) 的文件。
例子:
read -p "...what are you looking for: " iwant
read -p "...what should not be included: " idontwant
iwant="blue car"
idontwant="red car"
假设我有以下文件:
-rw-rw-r--. 1 terpentin terpentin 45 Jun 8 16:04 blue.car
-rw-rw-r--. 1 terpentin terpentin 44 Jun 8 16:05 mixed.car
-rw-rw-r--. 1 terpentin terpentin 40 Jun 8 16:04 red.car
find . -type f -print -exec cat {} \;
./mixed.car
blue car
red car
blue car
./red.car
red car
red car
red car
./blue.car
blue car
blue car
blue car
怎么可能只得到文件“./blue.car”作为结果?
原始内容包括数百个长文本文件,因此尽可能节约资源非常重要。
答案1
使用
find . -type f ! -exec grep -q "$idontwant" {} ';' -exec grep -q "$iwant" {} ';' -print
或者
find . -type f -exec grep -q "$iwant" {} ';' ! -exec grep -q "$idontwant" {} ';' -print
- 命令中的术语(有时称为“谓词”)
find
的特征为测试(例如,-type f
)和行动(例如,-print
和-delete
)。从手册页中可能很难弄清楚这-exec
两者都是 行动和一个 测试。所以,正如寻找 。 -type f -mtime -30 -name '*.txt' -可读 -size +5测试6 测试7 测试8……
连续将搜索范围缩小到满足所有条件的文件(满足所有指定的测试),因此寻找 。 -执行命令1{} ';' -执行命令2{} ';' -执行命令3{} ';' ……
查找所有命令都成功的文件。 - 任何
find
测试都可以通过在其前面加上 来否定(反转)!
。因此find . ! -type d
可以查找普通文件、符号链接、命名管道、套接字和设备文件——除了目录之外的所有文件。 - 请注意,
! -exec grep …
不等于-exec grep -v …
。-exec grep -v …
将找到至少有一行不匹配的文件。! -exec grep …
会在哪里找到文件不线条匹配。 - 选项
-q
togrep
是 的正式同义词--quiet
,但它也意味着快的。它不写入任何输出(可能除了错误消息(如果适用)),而且一旦找到匹配项它就会退出 - 它不会读取每个文件到末尾来查找每一个匹配。 (当然,如果文件不包含任何匹配项,则grep
必须完整读取它才能确定。) - 所以 (长话短说)命令查找其文件
grep -q“$iwant” 文件
成功并且grep -q“$idontwant”文件
失败(因为我们在它前面加上了!
)。 - 这两个命令在功能上是等效的,但可能具有不同的性能(即,可能需要不同的运行时间)。如果只有几个文件包含搜索字符串,
寻找 。 -type f -exec grep -q "$iwant" {} ';' ! -exec grep -q "$idontwant" {} ';' -打印
会更快,因为这grep "$iwant"
会消除大部分文件。如果许多文件都包含这两个字符串,则寻找 。 -输入f! -exec grep -q "$idontwant" {} ';' -exec grep -q "$iwant" {} ';' -打印
会更快,因为这! grep "$idontwant"
会消除大部分文件。
答案2
我们可以通过GNU grep
明智地选择 regex 和 grep 选项来执行文件名提取:
$ grep -lzPsr '(?s:(?=.*blue)(?!.*red))' .
我们在 slurp 模式 (-z) 下运行 grep,其中整个文件被视为一大行。
-l 将列出与正则表达式匹配的文件的文件名。
-r 将在当前目录下的所有文件上递归运行。
-s 将使 grep 静音,不发出任何警告。
正则表达式将查找文件中是否存在蓝色且不存在红色,以便回答“是”。
-P 在 grep 中调用 Perl 正则表达式引擎,以便我们可以利用 pcre 正则表达式的优势。