!!! 警告:这不是一次演习 !!!

!!! 警告:这不是一次演习 !!!

根据这个问题和答案: 删除文件但排除列表中的所有文件

这段代码完全满足我的需要,除了它不适用于子目录。

for i in *; do
    if ! grep -qxFe "$i" filelist.txt; then
        echo "Deleting: $i"
        # the next line is commented out.  Test it.  Then uncomment to removed the files
        # rm "$i"
    fi
done

它似乎只是匹配文本文件中的文本,而不是将每个新行视为路径。因此,当文本文件包含以下内容时:

./leaveme.jpg
./i am staying.gif
./james/leaveme.gif
./james/

它还会尝试删除 james 目录吗?它还会忽略 james 目录中任何其他应删除的文件。

有什么方法可以让它识别文本文件中的完整路径吗?我有数千个子目录,因此在每个单独的目录上运行此脚本将需要很长时间。

答案1

尝试rsync利用其排除选项的帮助,如下所示:

rsync --dry-run -v -r --remove-source-files \
      --exclude-from='/path/to/excludefile.txt' /path/to/source/ /path/to/somewhere/to_delete

笔记

  • 该命令正在--dry-run模式下运行;将其移除以采取实际操作。
  • 运行之前,请确保您的excludefile.txt位于/path/to/source路径之外,或者将其自身添加到excludefile.txt文件中以排除删除。
  • 如果操作完成后有空目录,rsync 无法删除,因此你需要手动删除它们,请尝试

    find /path/to/source -type d -empty -ok rmdir {} \;
    

    如果您不想确认删除每个目录,请将命令更改为以下命令。

    find /path/to/source -type d -empty -delete
    
  • 参见此处演示运行添加

  • 最后一步,仔细检查移动到的文件和目录/path/to/somewhere/to_delete,如果对结果满意,则删除整个目录。

    \rm -rfi /path/to/somewhere/to_delete  # -i switch is used for confirmation, remove it if you don't needed
    

答案2

您可以使用find . -type f以递归方式列出所有文件及其完整路径。-type f省略所有目录并仅列出文件。但这里filelist.txt应该包含我们需要从删除中排除的文件的完整路径。

IFS=$'\n'
for i in $(find . -type f); do
    if ! grep -qxFe "$i" filelist.txt; then
        echo "Deleting: $i"
        # the next line is commented out.  Test it.  Then uncomment to remove the files
        # rm "$i"
    fi
done

答案3

假设你的exclude.txt样子是这样的:

leaveme.jpg
i am staying.gif
james/leaveme.gif

所有子目录和文件都位于一个父目录并且您的exclude.txt以及delete.sh位于该父目录之外。

下面的脚本将执行以下操作:

  • exclude.txt逐行读取文件名。
  • 查找父目录下所有匹配的文件名,并通过添加.KEEP后缀来标记。
  • 找到父目录下所有没有标明后缀的文件.KEEP并删除。
  • 找到父目录下的所有空子目录并删除。
  • .KEEP从保存的文件中删除后缀并将其恢复为原始名称。

!!! 警告:这不是一次演习 !!!

运行时,脚本将执行上述所有操作立即地。请勿在您的实际目录上运行它,除非您先测试它以查看结果是否符合您的要求。

要首先测试脚本,请在结构和命名与所需目录相似的假复制目录上运行它。

您还可以通过更改此行来查看在实际删除文件之前将首先删除哪些文件:

find "$path" -type f ! -name "*.KEEP" -exec rm {} \;

用这一行:

find "$path" -type f ! -name "*.KEEP" -exec echo {} "Will be deleted!" \;

步入2下面只打印要删除的文件的名称而不是实际删除它们。


要创建和使用脚本,请按照以下步骤操作:

  1. 在您的主目录中创建并编辑一个脚本文件,并delete.sh通过在终端中运行以下命令来命名它:

    nano ~/delete.sh

  2. 将以下代码复制并粘贴到编辑器中,/path/to/parent/directory/用包含要删除的文件的目录的完整路径替换,并替换/path/to/exclude.txt为您的完整路径exclude.txt

#!/bin/bash
path="/path/to/parent/directory/"
filelist="/path/to/exclude.txt"

while IFS=$'\n' read filename
        do
                mv -n "$path$filename" "$path$filename.KEEP"
        done < "$filelist"

find "$path" -type f ! -name "*.KEEP" -exec rm {} \;

find "$path" -type d -empty -delete

while IFS=$'\n' read filename
        do
                mv -n "$path$filename.KEEP" "$path$filename"
        done < "$filelist"


  1. 保存脚本文件并按Ctrl+X然后按退出编辑器Y

  2. 通过在终端中运行以下命令使脚本文件可执行:

    chmod +x ~/delete.sh

  3. 通过在终端中运行以下命令来运行脚本:

    bash ~/delete.sh

完成后,只有列出的文件exclude.txt留在您的父目录下。

相关内容