我用来grep
搜索 1 TB 的文件。我想要 grep 文件名并将名称放入文本文件中,并且我想要cp
与 dir 匹配的所有文件/home/user/matches
。我想完成这两项任务,而无需使用 grep 两次搜索所有文件。
我的想法是使用 grep 将文件名输出放入文本文件中
grep -ril "xxx" . >> /home/user/matches/output-filename.txt
现在用作output-filename.txt
cp 的输入并使 cp 逐行执行。我怎么做? awk?或者你们有其他想法来避免两次搜索所有文件
答案1
文件路径是除 0 之外的字节序列;它们不一定是文本,更不用说文本行了。特别是文件路径
- 可能包含换行符
- 可能包含不形成有效字符的字节序列
- 可能比 LINE_MAX 长
GNU 实现grep
(添加该选项的那个-r
)可以以非文本格式打印路径,并且-Z
可以安全地进行后处理。例如,GNUxargs
可以使用其选项处理该格式-0
:
xargs -r0 -a <(
grep -rilZ xxx . |
tee file.list
) cp -it /home/user/matches --
(这里也假设 GNUcp
作为其-t
选项)
如果您想使用 GNU 以人类可以理解的文本格式打印该列表printf
:
xargs -r0a file.list printf '%q\n'
1 嗯,它应该确保无法解码的字节,因为字符被呈现为$'\234'
表示形式。对于包括换行符在内的控制字符也是如此,它被呈现为$'\n'
.这解决了上面的前两点,但它不能保证输出的行数会短于LINE_MAX
(但话又说回来,标准文本实用程序的 GNU 实现通常对它们支持的行数没有限制)。
答案2
您可以使用find
一对链接的exec
命令。也许不是最有效的解决方案,因为它grep
为每个文件(以及cp
每个匹配的文件)调用,但无论文件名中的字符如何,它都会起作用:
mkdir -p ~/matches
find -type f -exec grep -il 'xxx' {} \; -exec cp -p {} ~/matches/ \; > ~/matches/output-filename.txt