删除不在列表中的所有文件和文件夹

删除不在列表中的所有文件和文件夹

给定一个包含我想要保留的路径的文本文件,例如:

/mnt/cache/vfs/cf/A/file
/mnt/cache/vfs/cf/B/file2

我想清除下面的所有内容,/mnt/cache/vfs/cf除非它在我的文本文件中

所以/mnt/cache/vfs/cf/Z/file3被删除等等

文本文件很大,文件名中包含空格和可能的重音符号或其他特殊字符

答案1

我会列出文件系统中的文件,删除要保留的文件集中存在的文件,然后删除其余文件。

在这里,我始终使用以 NULL 结尾的文件名,这样就不会混淆xargs包含空格的文件名及其空格分隔的部分:

find /mnt/cache/vfs/cf -type f -print0 |
    LC_ALL=C sort -z |
    LC_ALL=C comm -z -23 - <(LC_ALL=C sort list-of-files-to-keep.list | tr '\n' '\0') |
    xargs -0 printf '%s\n' {}

当您准备好执行删除时替换printf '%s\n'为。rm --

comm命令获取两个已排序的文件并逐行比较它们。输出的第一列仅是第一个文件中的条目,第二列仅是第二个文件中的条目,第三列是两个文件中的条目。-1-2和限定符-3禁止相应列的输出,因此我们comm -23将输出仅出现在第一个文件中的行(-,即标准输入)。

我强制语言环境C以彼此一致的方式工作(sort需要排序的输入),并且还使每一行都以确定性的方式排序(某些语言环境对字符集进行相同的排序,因此这样的字符一组可能会以不一致的方式排序)。commcomm

答案2

我会使用这样的简单单行:

for FILE in $(ls /mnt/cache/vfs/cf); do grep "$FILE" keep_files.txt || rm "/mnt/cache/vfs/cf/$FILE"; done

但我会根据您要删除的文件数量,建议始终将它们移动到临时目录中,以确保您不会意外删除所需的文件:)

答案3

我会做什么:

shopt -s extglob
cd /mnt/cache/vfs/cf
{   printf 'rm !('; awk -F'/mnt/cache/vfs/cf' '{print $2}' file |
    paste -sd '|'
} | sed 's/$/)/'

当您对输出感到满意时,您可以将整个片段输入bash

shopt -s extglob
cd /mnt/cache/vfs/cf
{   printf 'rm !('
    awk -F'/mnt/cache/vfs/cf' '{print $2}' file |
    paste -sd '|'
} | sed 's/$/)/' | 
    bash

http://mywiki.wooledge.org/glob#extglob
https://www.gnu.org/software/bash/manual/html_node/Pattern-Matching.html

相关内容