关于unix:find sed,文件名输出

find + sed, filename output

我有目录:D:/Temp,其中有很多带有文本文件的子文件夹。每个文件夹都有"file.txt"。在某些 file.txt 文件中有一个词 - "pattern"。我想检查有多少模式词,并获取该 file.txt:

的文件路径

1
find D:/Temp -type f -name"file.txt" -exec basename {} cat {}  \\; | sed -n '/pattern/p' | wc -l

输出应该是:

1
2
3
4
5
4
D:/Temp/abc1/file.txt
D:/Temp/abc2/file.txt
D:/Temp/abc3/file.txt
D:/Temp/abc4/file.txt

或类似的。


你可以使用 GNU grep :

1
grep -lr --include file.txt"pattern""D:/Temp/"

这将返回文件路径。

1
grep -cr --include file.txt"pattern""D:/Temp/"

这将返回计数(计算模式出现次数而不是文件数)

标志说明:

  • -r 使 grep 递归地浏览它的目标,然后可以是一个目录
  • --include <glob> 使 grep 将其递归浏览限制为与 <glob> 匹配的文件。
  • -l 使 grep 只返回文件路径。此外,它会在遇到该模式后立即停止解析文件。
  • -c 使 grep 只返回匹配的数量


如果您的文件名不包含空格,那么您只需要:

1
awk '/pattern/{print FILENAME; cnt++; nextfile} END{print cnt+0}' $(find D:/Temp -type f -name"file.txt")

上面使用了 GNU awk for nextfile.


我读你问题的方式,我会像这样回答:

  • 一些但不是所有的 file.txt 文件都包含 pattern
  • 你想要一个通向 pattern 的 file.txt 的路径列表,并且
  • 您希望在每个文件中计数 pattern

有几个选项。 (总是有多种方法可以做任何事情。)

如果你的 bash 是 4 或更高版本,你可以使用 globstar 递归遍历目录:

1
2
3
4
5
6
7
8
shopt -s globstar

for file in **/file.txt; do
  if count=$(grep -c 'pattern'"$file"); then
    printf"%d %s\
""$count""${file%/*}"
  fi
done

这是因为 if 评估将失败的 grep(即零次出现)视为 FALSE,因此不会打印结果。

请注意,这可能会产生很大的影响,因为它会在找到的每个文件上启动一个单独的 grep。一个更轻量级的替代方法可能是在 fileglob 上运行单个 grep,并解析结果:

1
2
3
shopt -s globstar

grep -c 'pattern' **/file.txt | grep -v ':0$'

这也取决于 bash 4,当然,如果您有数百万个文件,您可能会超过 bash\\ 的命令行最大长度。这个输出是显而易见的,但是如果你的文件名包含冒号,你需要小心地解析它。 IE。 cut -d: -f2 可能无法剪切它。

另一个利用 grep 而不是 bash 的选项可能是:

1
grep -r --include 'file.txt' -c 'pattern' ./ | grep -v ':0$'

这使用了 GNU grep 的 --include 选项,该选项修改了 -r 的行为(递归)。它应该可以在 Linux、FreeBSD、NetBSD、OSX 中运行,但不适用于 OpenBSD 或大多数 SVR4(Solaris、HP/UX 等)上的默认 grep。

请注意,我没有测试过这些。不承担任何责任。可能含有坚果。


我会用

1
2
3
4
find D:/Temp -type f -name"file.txt" -exec dirname {} \\; > tmpfile
wc -l tmpfile
cat tmpfile
rm tmpfile


以前我用过:

1
grep -Hc"pattern" $(find D:/temp -type f -name"file.txt")

这仅在找到 file.txt 时才有效。否则,您可以使用以下内容来说明何时找到或未找到两个文件:

1
searchFiles=$(find D:/temp -type f -name"file.txt"); [[ ! -z"$searchFiles" ]] && grep -Hc"pattern" $searchFiles

这个输出看起来更像:

1
2
3
4
D:/Temp/abc1/file.txt 2
D:/Temp/abc2/file.txt 1
D:/Temp/abc3/file.txt 1
D:/Temp/abc4/file.txt 1


试试这个安全标准的版本:

1
find D:/Temp -type f -name file.txt -printf"%p\\0" | xargs -0 bash -c 'printf"%s""${@}"; grep -c"pattern""${@}"' | grep":[1-9][0-9]*$"

对于在 D:/Temp 目录和子目录中找到的每个 file.txt 文件,xargs 命令打印文件名和包含 pattern (grep -c) 的行数。

最后的 grep":[1-9][0-9]*$" 只选择计数大于 0 的文件名。


我建议你使用两个命令:一个用于查找所有文件:

1
find ./ -name"file.txt" -exec fgrep -l"-pattern" {} \\;

另一个数数:

1
find ./ -name"file.txt" -exec fgrep -l"-pattern" {} \\; | wc -l


应该这样做:

1
2
find . -name"file.txt" -type f -printf '%p\
' | awk '{print} END { print NR }'