我在 filesdir 文件夹中有大约 50000 个文件 (.txt) 和更多项目。这些文件中的值:“fax”、“phone”、“address”以不同的配置显示。我需要查找所有包含“fax”和“phone”但不包含“address”的文件。我尝试使用几个 grep 命令进行 for 循环。ls 给出“参数太多”。所以我尝试了:
find /filesdir/ -maxdepth 1 -name '*.txt' -exec grep -l 'fax' \; grep -l 'phone' \; grep -l -v 'address'
为什么它不起作用?
答案1
git grep
您可以使用git grep
布尔表达式组合多个模式,例如:
git grep --all-match --no-index -e "fax" --and -e "phone" --and --not -e "address"
您可以将不同的图案与布尔值诸如--and
、--or
和 之类的表达式--not
。
--all-match
当给出多个模式表达式时,指定此标志以将匹配限制为包含所有行的文件。
--no-index
搜索当前目录中不受 Git 管理的文件。
-l
//--files-with-matches
仅--name-only
显示文件的名称。
-e
下一个参数是模式。默认使用基本正则表达式。
其他需要考虑的参数:
--threads
要使用的 grep 工作线程的数量。
-q
//--quiet
不--silent
输出匹配的行;匹配时以状态 0 退出。
要更改图案类型,您还可以使用-G
/ --basic-regexp
(默认)、-F
/ --fixed-strings
、-E
/ --extended-regexp
、-P
/ --perl-regexp
、-f file
和其他。
查找man git-grep
更多帮助。
grep
以下是grep
使用链式语法命令替换:
grep -L "address" $(grep -l "phone" $(grep -rl "fax" .))
解释:
- 查找具有“传真”模式的文件名 (
grep -rl "fax" .
)。 - 过滤器找到具有“电话”模式的文件名(
grep -l "phone" $(cmd)
)。 - 进一步过滤以排除不包含
address
(grep -L "address" $(cmd)
)的文件。
如果你正在处理大数据,请考虑使用ripgrep
反而。
find
上面的例子可能不适用于带有空格的文件,所以这里是带有的版本find
:
find . -type f -name '*.txt' \
-execdir bash -c 'grep -L "address" "$(grep -l "phone" "$(grep -l "fax" "{}")")"' ';' \
2>/dev/null
也可以看看:检查文件中是否存在多个字符串或正则表达式
答案2
有几个原因会导致它不起作用:
- 您省略
{}
了-exec
- 您正在尝试通过一次调用执行
-exec
多个命令grep
- 我怀疑你的逻辑有缺陷,因为 find 的默认操作是合乎逻辑的,
AND
而你可能想要fax
ORphone
ANDnot address
我还没有完全测试过,但我想你想要更多类似的东西
find /filesdir/ -maxdepth 1 -name '*.txt' -exec grep -q 'fax\|phone' {} \; -exec grep -lv 'address' {} \;
答案3
在每个文件的一行上打印文件名及其内容
我认为这个命令行可以做到这一点:
find -maxdepth 1 -name "*.txt" -exec echo "{} :" \; -exec cat {} \; -exec echo EOF \;| tr '\n' ' '|sed 's/EOF /\n/g'|grep -iv 'address'|grep -i 'fax'|grep -i 'phone'
解释:
对于每个文件(由 找到
find
)- 回显文件名
- 打印内容
- 打印文件结束标志(应该与文件内部的内容不同。请谨慎选择此标志!我使用 EOF,您可能需要其他东西。
对于整个输出
- 将换行符转换为空格,使所有内容都显示在一行上
- 将文件结束标志转换为换行符
现在每个文件的内容都在单独的一行中,适合
grep
。最后
- 跳过包含“地址”的行
- 从剩余的输出中选择包含“fax”的行
- 从剩余输出中选择包含“phone”的行
仅打印文件名
上面的命令行打印文件名和文件内容(合并为一行),这有利于测试,但不适合处理数千个文件。
以下命令行仅打印文件名。它使用“:::”将每个文件名与文件内容分隔开。
find -maxdepth 1 -name "*.txt" -exec echo "{} :::" \; -exec cat {} \; -exec echo EOF \;| tr '\n' ' '|sed 's/EOF /\n/g'|grep -iv 'address'|grep -i 'fax'|grep -i 'phone' | sed 's/ :::.*//'
答案4
查找不包含该模式的文件(兼容包含空格/或换行符的文件)address
:
find -type f ! -exec grep -q 'address' {} \; -print
并仅打印那些包含模式的fax
和 phone
在整个文件中以任何顺序排列:
find -type f ! -exec grep -q 'address' {} \; \
-exec grep -qP '(?s)(?=.*?fax)(?=.*?phone)' {} \; -print
或者 POSIXly:
find -type f ! -exec grep -q 'address' {} \; \
-exec grep -q 'fax' {} \; \
-exec grep -q 'phone' {} \; -print
\n
或者假设文件名中没有ewline,那么:
grep -lP '(?s)(?=.*?fax)(?=.*?phone)' * |xargs -d'\n' grep -L address
(?=pattern)
:正向前瞻:正向前瞻结构是一对括号,左括号后跟问号和等号。(?s)
已知的“dot-all”告诉grep让点也.
能够匹配ewline 字符。\n
表示
.*?
匹配.
出现零次或多次的任意字符*
,且这些字符是可选的,后跟一个模式(fax
或phone
)。表示匹配?
其前的所有内容都是可选的(表示匹配的所有内容出现零次或一次.*
)