我想编写一个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来查找包含至少两个文件的目录,一个匹配一个模式,另一个匹配另一个模式,但这两个模式必须由不同的文件来满足吗?
感谢。
不过,我正在使用 find(GNU findutils)4.4.2。但是,我只是对人们提出的答案感兴趣。我已经完成了不太优雅的解决方案,但很高兴看到。它始终是有益的和有教育意义的。
答案 0 :(得分:4)
我无法想办法单独查找条件,但当然你总是可以使用-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。根据您的要求,输出是包含符合条件的文件的目录列表。如果单个目录中存在多个uniq
匹配项,则输出将通过*.py
进行过滤。
根据Etan的评论更新:
请注意,为了适应包含* .py和Makefile的当前(最顶层)目录的可能性,glob是**/./*.py
而不是**/*.py
。结果导致每个匹配的路径以点结束。虽然这仍然会找到所有目标目录(/foo/bar/.
与/foo/bar
相同),如果它困扰您,您可以通过在{{1之后添加| sed 's:/\.::'
来删除尾随点路径段}}。添加这样的过滤器会使输出看起来与基于uniq
的解决方案相同。
答案 1 :(得分:2)
尝试使用bash:
shopt -s globstar nullglob
for i in **/Makefile; do i="${i%/*}"; x=( "$i"/*.py ); [[ -n ${x[0]} ]] && echo "$i"; done
输出:
path1 path3/path4
答案 2 :(得分:1)
假设您只想打印出直接公共父目录而不是匹配的文件名,那么我认为这样可行。 (虽然我觉得必须有更好的方法来做到这一点。)
注意:GNU find
需要-printf
。
find "$topdir" -name '*.py' -printf '%h\0' | xargs -0 -I {} find {} -mindepth 1 -maxdepth 1 -name Makefile -printf '%h\n' | sort -u
对于非GNU find
选项(从ghoti's handiwork修改(未经测试):
find . -name '*.py' -exec sh -c 'for file; do d=$(dirname "$file"); test -f "$d"/Makefile && printf "%s\n" "$d"; done' -- {} \+
-exec ;
为每个匹配的文件运行一次命令。 -exec +
汇总一个命令行,其中包含适合单个命令的文件,因此对于大型匹配文件列表,运行许多更少的shell实例。
答案 3 :(得分:1)
我建议使用进程替换在while read
循环中使用shopt -s nullglob
while IFS= read -rd '' dir; do
ary=("$dir"/*.py)
[[ -f "$dir"/Makefile && ${#ary[@]} -gt 0 ]] && echo "$dir"
done < <(find . -type d -print0)
:
find
while
命令将查找当前目录中的所有目录,并在*.py
循环内部检查是否存在Makefile
个文件和service_category_selection
那些目录。
答案 4 :(得分:-1)
find
有一个-o
标志,可以组合多种模式。像这样:
find \( [pattern for path1] -o [pattern for path2] \)