给定一个包含我想要保留的路径的文本文件,例如:
/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
需要排序的输入),并且还使每一行都以确定性的方式排序(某些语言环境对字符集进行相同的排序,因此这样的字符一组可能会以不一致的方式排序)。comm
comm
答案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