删除 Linux 中所有文件夹(除非它们具有特定文件类型)

删除 Linux 中所有文件夹(除非它们具有特定文件类型)

我正在寻找一个命令或 bash 脚本来删除所有文件夹,除非它们在第一级子文件夹中具有特定文件类型 (*.pdf)。

folder01
  a.txt
  y.txt

folder02
  b.pdf
  z.txt

folder03
  h.txt
  folder03.1
    c.pdf

在上面的例子中folder01folder03需要删除。

我的尝试:

#!/bin/bash

shopt -s globstar

# Loop through every subdirectory.
for d in **/; do
    f=("$d"/*)
    if [[ -f "$f" && ! "${f##*/}" =~ ^*.pdf$ ]]; then
        # `echo` to ensure a test run; remove when verified.
        echo rm -r -- "$d"
    fi
done

答案1

这似乎运行良好(编辑:仅当它有一个 pdf 文件时):

for d in */; do
  if ! [ -f $d/*.pdf ]; then 
    echo "Will remove $d"
  fi
done

-f在指定路径下查找文件;-e一般会查找某物在那条路上)

编辑:为了考虑带有空格的路径和单个目录中的多个 PDF 文件,您可能需要使用find,例如:

for d in */; do
  if [[ -z $(find "$d" -maxdepth 1 -name "*.pdf" -type f) ]]; then 
    echo "Will remove $d"
  fi
done

我将其从 改为**/因为*/对于您的用例,我相信您会这样做不是想要globstar**/- 这些将使其循环遍历子目录,例如:

> for d in **/; do echo $d; done
folder01/
folder02/
folder03/
folder03/folder03.1/

在测试用例中,这似乎不会改变最终结果,但如果您只对.pdf第一级子目录感兴趣,则不需要循环遍历任何子目录。

如果您想要删除任何级别都没有 pdf 的目录,您可以将 if 语句更改为:

if ! [ -f $d/**/*.pdf ]; then

-maxdepth 1编辑:或从命令中删除find

答案2

以下命令打印即将被删除的目录的路径名:

# cd to the right directory first

find . -type d ! -name . \( -exec [ -r {} ] \; -o ! -prune \) \
-exec sh -c '
   set -- "$1"/*.pdf
   ! [ -e "$1" ]
' find-sh {} \; -prune -print

如果结果看起来正确,则-exec rm -r {} +在 之后附加-print。即使您的find支持-delete,不要使用它,因为它不能删除非空目录。

该代码通过为每个考虑的目录运行一个 shell 来工作。shell 使用通配符来检测*.pdf目录中匹配的文件。几点说明:

  • -prune末尾附近可防止进入无论如何都会被删除的目录。例如,在我们有资格删除后find检查是没有意义的。要明确的是:删除意味着删除,即使中有匹配的文件。./folder03/folder03.1./folder03./folder03rm -r./folder03/folder03.1*.pdffolder03.1

  • ! -name .如果起始路径是 ,则是-mindepth 1GNU 的POSIX 等效版本(不可移植)。如果起始路径是 ,则可移植地执行此操作很容易,否则就不那么容易了。因此我设计了解决方案,因此您需要事先进入正确的目录。find..cd

  • *.pdf不匹配隐藏文件(点文件)。您的尝试也使用了通配符,因此我想这对您来说没问题。

  • *.pdf区分大小写。不区分大小写的模式是*.[pP][dD][fF]

  • *.pdf火柴文件任何类型的文件,不一定是常规文件。它只是名字。在您的一条评论中,您写道“*.pdf作为主要规则,它是安全的”。就这样吧。

  • 如果没有匹配的文件,*.pdf则在 POSIX shell 中保留其文字形式;因此至少有一个“匹配”,我们不知道它是否匹配。在具有更多功能的 shell 中(例如在 Bash 中),您可以对此采取一些措施,但我希望我的代码具有可移植性。这就是为什么我测试文件系统中是否存在第一个“匹配”(! [ -e "$1" ])而不是依赖匹配的数量。

  • 您不需要能够cd访问正在测试的每个目录。

  • 如果您无权读取目录,则 shell 代码将无法*.pdf在其中找到任何内容(即使此类文件确实存在)。尝试访问rm -r目录将失败(除非目录已经为空),将生成一些错误消息。-exec [ -r {} ] \; -o ! -prune阻止find尝试读取此类目录的内容并尝试对其进行测试、删除它。如果不允许读取的目录是一个问题,您可能需要根据需要调整解决方案的这一部分。

  • find-sh解释如下:中的第二个 sh 是什么sh -c 'some shell code' sh

答案3

假设特定文件类型为 *.pdf >

  1. 将您不想删除的包含 *.pdf 的目录放入文件删除中

    find -name *.pdf -exec dirname {} ';' > temp && sed 's/\.\///g' temp| sed 's![^/]$!&/!'> remove.txt

  2. 将当前路径下的所有目录放入文件 current.txt

    ls -d */>current.txt

  3. 比较 current.txt 和 remove.txt 并从 current.txt 中删除不在 remove.txt 中的文件

    comm -23 <(sort current.txt) <(sort remove.txt)|sed 's/^/"/g' | sed 's/$/"/g' | xargs rm -r

&& rm current.txt remove.txt注意:如果您只想要带有 *.pdf 的目录,则可以附加或删除当前路径中的所有文件和目录ls> current.txt,然后改为使用第二步。这将删除在过程中已存在和创建的所有“文件”

相关内容