天真的方法是find dir1 dir2 dir3 -type d -name .git | xargs -I {} dirname {}
,但对我来说太慢了,因为我在 git 存储库中有很多深层文件夹结构(至少我认为这是原因)。我已经读过关于我可以prune
用来防止 find 在找到某些内容后递归到目录中的内容,但有两件事。我不确定这是如何工作的(我的意思是我不明白prune
虽然我已经阅读了手册页),第二个它在我的情况下不起作用,因为它会阻止find
递归到.git
文件夹但不是全部其他文件夹。
所以我真正需要的是:
对于所有子目录,检查它们是否包含.git
文件夹,如果它停止在此文件系统分支中搜索并报告结果。如果这也能从搜索中排除任何隐藏的目录,那就太完美了。
use*_*095 11
好的,我仍然不完全确定它是如何工作的,但我已经测试过它并且它有效。
.
??? a
? ??? .git
? ??? a
? ??? .git
??? b
??? .git
6 directories, 0 files
% find . -type d -exec test -e '{}/.git' ';' -print -prune
./a
./b
Run Code Online (Sandbox Code Playgroud)
我期待更快地做出同样的事情。
理想情况下,您希望爬行目录树以查找包含条目的目录.git
,并停止进一步搜索这些目录(假设您在 git 存储库中没有更多的 git 存储库)。
问题是,使用 standard 时find
,执行这种检查(目录包含条目.git
)涉及生成一个test
使用谓词执行实用程序的进程-exec
,这比列出几个目录的内容效率要低。
一个例外是,如果您使用shellfind
的内置函数(由@schilybosh
开发的 Bourne shell 的 POSIX 化分支),它有一个谓词来评估 shell 中的代码,而无需生成新的 sh 解释器:-call
#! /path/to/bosh -
find . -name '.?*' -prune -o \
-type d -call '[ -e "$1/.git" ]' {} \; -prune -print
Run Code Online (Sandbox Code Playgroud)
或者perl
使用File::Find
:
perl -MFile::Find -le '
sub wanted {
if (/^\../) {$File::Find::prune = 1; return}
if (-d && -e "$_/.git") {
print $File::Find::name; $File::Find::prune = 1
}
}; find \&wanted, @ARGV' .
Run Code Online (Sandbox Code Playgroud)
比zsh
's printf '%s\n' **/.git(:h)
(下降到所有非隐藏目录)或 GNU find
's (在每个非隐藏目录的新进程中find . -name '.?*' -prune -o -type d -exec test -e '{}/.git' \; -prune -print
运行一个命令)更长,但更快。test
2022 编辑. 最新版本的 busybox 中的小程序find
能够运行其[
或test
小程序,而无需分叉进程并在内部重新执行自身,因此,尽管它仍然不如 bosh 或 perl 方法那么快:
busybox find . -type d -exec [ -e '{}/.git' ] ';' -prune -print
Run Code Online (Sandbox Code Playgroud)
在我的测试中,比 GNU 等效项快几个数量级find
(在包含 git / cvs / svn 存储库混合的本地样本上,总共超过 100000 个目录,我得到的 bosh 为 0.25 秒,perl 为 0.3 秒,busybox 为 0.7 秒)find
,GNU 为 36 秒find
,GNU 为 2 秒find . -name .git -printf '%h\n'
(给出不同的结果,因为它还.git
在 git 存储库的子目录中查找文件)。
归档时间: |
|
查看次数: |
11056 次 |
最近记录: |