![如何 grep 目录中的每个文件查找关键字并输出关键字及其在其中找到的文件名?](https://linux22.com/image/151906/%E5%A6%82%E4%BD%95%20grep%20%E7%9B%AE%E5%BD%95%E4%B8%AD%E7%9A%84%E6%AF%8F%E4%B8%AA%E6%96%87%E4%BB%B6%E6%9F%A5%E6%89%BE%E5%85%B3%E9%94%AE%E5%AD%97%E5%B9%B6%E8%BE%93%E5%87%BA%E5%85%B3%E9%94%AE%E5%AD%97%E5%8F%8A%E5%85%B6%E5%9C%A8%E5%85%B6%E4%B8%AD%E6%89%BE%E5%88%B0%E7%9A%84%E6%96%87%E4%BB%B6%E5%90%8D%EF%BC%9F.png)
我有一个包含 2000 多个文本文件的目录。我正在尝试制作一个脚本:
- 读取 IP 地址列表
ip.txt
- Cats 目录中的每个文件
- Greps 每个文件的 IP 地址
如果找到关键字,则将关键字和文件名回显到文件。
输出应该是这样的:
$ cat
results.txt
192.168.2.3 was found in 23233.txt
192.168.4.0 was found in 2323.txt
目前我有这个:
while read p; do
for filename in *.txt; do
if cat $filename | grep "$p"
then echo "$p" is "$filename" | tee result.txt
fi
done
done<ips.txt
然而,这也会将所有文件名回显到结果中。我怎样才能解决这个问题?
答案1
首先,cat
在不需要时不使用它来保存它。而不是:
cat haystack | grep needle
您可以简单地:
grep needle haystack
至于你的脚本:
> results.txt # start with a fresh file for every run
while read ip; do
grep "$ip" * | grep -Ev 'results\.txt|ips\.txt' >> results.txt
done < ips.txt
grep
-into-管道grep
用于防止将输入和输出文件中的条目添加到输出文件中。
如果你有无数的文件需要检查并且你得到了argument list too long
,我们可以使用一个工具,比如xargs
将我们的命令分成足够短的块,以便 shell 允许:
> results.txt # start with a fresh file for every run
while read ip; do
find . -type f -maxdepth 1 -not -name ips.txt -not -name results.txt -print0 | xargs -0 grep "$ip" >> results.txt
done < ips.txt
在这里,我们过滤掉了输入和输出文件,并使用逻辑输入find
,因此我们不再需要grep
输入grep
。
答案2
假设您的文件只有 IPv4 地址(没有 IPv6),您可以运行如下所示的命令:
find [dir1] -maxdepth 1 -type f -iname ip.txt -exec grep -H '[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*' {} \;
这应该可以处理无限数量的文件。你的输出看起来像这样[dir1]/ip.txt:1.2.3.4
。当然,您需要将“[dir1]”替换为实际目录(或者您可以省略此选项,在这种情况下 find 将仅使用您当前的工作目录)。如果您愿意,您可以指定多个目录。事实上,对于可以在 find 命令中放入多少个目录,不应该有任何真正的限制,只要将它们放入即可前“-max深度”参数。
答案3
如果你不喜欢 grep 的话,另一种选择是我很久以前用来取代 grep 的最喜欢的工具 -确认。它几乎可以放入您提供的脚本中并提供您需要的输出。 (默认情况下它是递归搜索,如果您不想搜索子文件夹中的文件,则值得注意)。
while read p; do
for filename in $(ack -l $p); do
echo "$p found in $filename" >> results.txt
done
done<ips.txt