使用“find”搜索包含特定文件类型 foo 的目录

使用“find”搜索包含特定文件类型 foo 的目录

我有几个目录,其中一些目录的深度为 3,其中包含混合文件类型。我需要做的是rm -rf所有不包含 filetype 的子目录foo

这可以通过find某种方式实现吗?我确实知道我可以像这样使用 find :

find . ! -name '*.foo' -delete

删除目录中不包含任何类型文件的所有文件*.foo。现在,我如何使用它,不仅删除所有不需要的文件,而且删除所有不包含的目录和子目录*.foo

答案1

(你的问题不清楚:如果一个目录包含some.foosome.bar,是否应该删除它?我将其解释为需要保留这样的目录。)

如果文件名不包含换行符且目录不匹配*.foo,则以下脚本应该可以工作。原理是从叶子向上(-depth)遍历目录,当*.foo遇到文件时,包含目录和所有父目录都被标记为protected。任何未受保护且已到达的文件*.foo都是要删除的目录。由于-depth遍历顺序的原因,目录总是在*.foo可能保护该目录的文件之后到达。警告:经过最低限度的测试,删除echo风险由您自行承担。

find . -depth -name '*.foo' -o -type d | awk '{
    if ($0 ~ /\.foo$/) {
        while (sub("/+[^/]+$", "")) {protect[$0]=1;}
    } else {
        if (!protect[$0]) {
            gsub("[\\\001-/]", "\\\\&"); # protect file names for xargs
            print;
        }
    }
}' | xargs echo rm -rf

这一次,我不会提出 zsh 解决方案。

答案2

我不太确定这可以仅使用 来完成,但我认为我们可以仅使用和 来find完成。bashfind

tree_contains_foo_files()
{
    # return true (0) as soon as we find a "*.foo" file
    find "$1" -type f -name "*.foo" -print0 |
        read -r -d $'\0' file && return 0

    return 1
}

find . -depth -type d -print0 |
while read -r -d $'\0' dir; do
    if ! tree_contains_foo_files "$dir"; then
        rm -rf "$dir"
    fi
done

给定这个测试树:

.
./dir1
./dir1/dir1.1
./dir1/dir1.1/dir1.1.1
./dir1/dir1.1/dir1.1.1/file.foo
./dir1/dir1.1/file.bar
./dir2
./dir2/dir2.1
./dir2/file.bar
./dir3

我得到这个结果:

rm -rf ./dir2/dir2.1
rm -rf ./dir2
rm -rf ./dir3

我认为这就是你想要的,即不要删除dir1,因为dir1/dir1.1/dir1.1.1包含file.foo

但请注意,它确实会多次处理目录,因此对于大型树来说可能会很慢。如果效率很重要,我会使用更强大的编程语言。

答案3

IIUYC,您可以先使用以下命令删除所有不需要的文件

find . ! -type f -name '*.foo' -delete

这可能会清空一些目录。然后您可以删除空目录(以及仅包含空目录的目录等),例如我的问题

find . -depth -mindepth 1 -empty -type d -exec rmdir -p -- {} +

答案4

如果不仅仅find允许,一个更简单的解决方案是:

find -type d -not -path . | while IFS='' read -r path; do [[ ! -e "$path/$notThisFile" ]] && echo "$path"; done

替换-e为您喜欢的任何测试。

这应该会打印所有不包含$notThisFile.


详细示例,其中包含该文件的所有非隐藏子目录都突出显示:

find -type d -not -path . | while IFS='' read -r path; do
  [[ ! -e "$path/$notThisFile" ]] && echo "$path"
done | sed -r 's~^([^.]*)/'"$notThisFile"'$~\033[1;37m\1\033[0m~''

相关内容