bash - 如何打印包含两个匹配两种不同模式的文件的目录?

标签 bash unix find

我想编写一个 bash 脚本(除其他外)查找 Makefile,其中 Makefile 与 python 文件(看起来像 *.py 的文件)位于同一目录中。

通过执行两个单独的查找和比较输出,我可以通过几个步骤相当不优雅地完成它,但我认为可能有一种方法可以执行一行查找命令?只是好像应该有办法?

所以

path1/Makefile
path1/Some.py
path2/Makefile
path3/Makefile
path3/path4/Makefile
path3/path4/Another.py

path1 将被打印。

path2 不会。

path3 不会被打印出来。 b/c python 文件需要处于同一级别。

path3/path4 将被打印。

所以一般的问题是,我可以使用 find 来查找包含至少两个文件的目录,一个匹配一个模式,另一个匹配另一个模式,但是两个模式必须由单独的文件满足吗?

谢谢。

顺便说一句,我正在使用 查找 (GNU findutils) 4.4.2。

但是,我只对人们提出的答案感兴趣。我已经完成了不优雅的解决方案,但很高兴看到。它总是有帮助和教育意义。

最佳答案

我想不出单独使用查找条件来做到这一点的方法,但当然你总是可以使用 -exec 来构造这样的东西:

find . -name '*.py' -exec bash -c 'test -f $(dirname "$1")/Makefile' -- {} \; -print

这将打印在同一目录中具有 Makefile 的 *.py 文件列表。如果您在最后一个正斜杠后去掉所有内容,您将只得到包含这些文件的目录,例如通过管道通过 sed 's:/[^/]*$::'

此解决方案的优点是仅运行单个 find,代价是为找到的每个 .py 文件生成一个 shell。请注意,test 是大多数 shell 中的内置函数。


您也可以单独在 bash 中执行此操作,完全绕过 find:

shopt -s globstar
for file in **/./*.py; do
  test "${file%/*}/Makefile" && echo "${file%/*}"
done | uniq

“globstar”选项允许 **/*.py 搜索子目录,就像 find 一样,通过这个解决方案,我们可以使用参数扩展来代替运行 dirname 的子 shell。正如您所要求的,输出是包含符合您条件的文件的目录列表。如果单个目录中存在多个 *.py 匹配项,则通过 uniq 过滤输出。

根据 Etan 的评论更新:

请注意,为了适应当前(最顶层)目录包含 *.py 和 Makefile 的可能性,glob 是 **/./*.py 而不是 **/*.py。结果导致每个匹配的路径都以点结尾。虽然这仍然会找到所有目标目录(/foo/bar/./foo/bar 相同),但如果它困扰您,您可以去除尾随通过添加 | 点路径段sed 's:/\.::'uniq 之后。添加这样的过滤器将使输出看起来与基于 dirname 的解决方案相同。

关于bash - 如何打印包含两个匹配两种不同模式的文件的目录?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33108966/

相关文章:

bash - 如何退出最近的 getopts 选项?

python - 从两个文件的特定列中查找匹配项

linux - 如何仅为特定应用程序更改核心模式?

replace - 如何在 Notepad++ 中的书签行中查找和替换

bash - 如何在 bash 中将包含空格的变量作为循环参数传递?

c - GDB 在 shell 生成时卡住

linux - 从 Linux shell 将多个目录复制到另一个多个目录

C++ find_if 另一个类的成员变量

linux - 查找shell脚本-日志(SUSE Linux, bash, if, find)

linux - 如果同一个文件中存在 CR 和 LF,sed 无法区分它们