Answers:
我意识到,任何询问如何删除文件的问题都必须格外小心。我的第一个答案太草率了,我没有想到文件列表可能格式错误,无法与egrep一起使用。我编辑了答案以减少这种风险。
这应该适用于名称中没有空格的文件:
首先重建您的文件列表,以确保匹配确切的文件名:
sed -e 's,^,^,' -e 's,$,$,' filelist > newfilelist
建立rm命令
cd your_directory
ls | egrep -vf newfilelist | xargs -n 1 echo rm > rmscript
检查rm脚本是否适合您(可以使用“ vim”或“ less”来完成)。
然后执行以下操作:
sh -x rmscript
如果文件名中带有空格(如果文件名中带有,"
则将无法使用):
ls | egrep -vf newfilelist | sed 's,^\(.*\)$,rm "\1",' > rmscript
当然,文件列表不应位于同一目录中!
编辑:
Nathan的文件列表包含与目录中所有文件匹配的名称(例如“ html”匹配“ bob.html”)。由于egrep -vf
吸收了所有流,因此没有删除任何内容。我添加了一个命令,在每个文件名前后加上“ ^”和“ $”。我很幸运,Nathan的文件列表是正确的。如果它是使用CR-LF结束行或其他空格进行DOS格式化的,则egrep不会保留任何文件,而所有文件都将被删除。
ls
提供目录文件名,egrep -vf filelist
过滤您的50个文件名。恐怕您删除了所有文件。
将参数预先构造为find
:
{
read -r
keep=( -name "$REPLY" ) # no `-o` before the first one.
while read -r; do
keep+=( -o -name "$REPLY" )
done
} < file_list.txt
find . -type f ! \( "${keep[@]}" \) -exec echo rm {} +
使用echo
零件查看将要构造的内容。卸下echo
零件以实际运行它。
##
# Demonstrate what files exist for testing.
# Show their whitespace:
~/foo $ printf '"%s"\n' *
" op"
" qr"
"abc"
"def"
"gh "
"ij "
"k l"
"keep"
"m n"
##
# Show the contents of the "keep" file,
# Including its whitespace:
~/foo $ cat -e keep
keep$
abc$
gh $
k l$
op$
##
# Execute the script:
~/foo $ { read -r; keep=( -name "$REPLY" ); while read -r ; do keep+=( -o -name "$REPLY" ); done } < keep
~/foo $ find . -type f ! \( "${keep[@]}" \) -exec rm {} +
##
# Show what files remain:
~/foo $ printf '"%s"\n' *
" op"
"abc"
"gh "
"k l"
"keep"
'
应该添加一些单引号()即keep=( -name \'"$REPLY"\' )
和keep+=( -o -name \'"$REPLY"\' )
。
与zsh
:
mylist=(${(f)"$(<filelist)"})
print -rl -- *(.^e_'(($mylist[(Ie)$REPLY]))'_)
它读取filelist
数组中的行,然后使用glob qualifiers / e
字符串来glob /仅选择数组中不存在的文件名:.
仅选择常规文件(D
如果列表中包含点文件,则添加),而否定的^e_'expression'_
仅选择用于表达式返回false,即如果它们的名称($REPLY
)不是数组的元素。
如果你对结果满意取代print -rl
与rm
实际删除文件:
rm -- *(.^e_'(($mylist[(Ie)$REPLY]))'_)
要递归选择和删除文件,请使用*/**
带有${REPLY:t}
glob修饰符的glob :
rm -- */**(.^e_'(($mylist[(Ie)${REPLY:t}]))'_)
运行以下脚本。
all_files
。not_to_be_deleted_files
)。not_to_be_deleted_files
,并
files_to_be_deleted
在2002年底not_to_be_deleted_files
,我们需要这2个文件。join
命令删除的文件,
并将输出重定向到files_to_be_deleted
文件。files_to_be_deleted
并删除该文件名中
提到的文件。脚本如下。
find /home/username/directory -type f | sed 's/.*\///' > all_files
echo all_files >> not_to_be_deleted_files
echo not_to_be_deleted_files >> not_to_be_deleted_files
echo files_to_be_deleted >> not_to_be_deleted_files
join -v 1 <(sort all_files_listed) <(sort files_not_to_be_deleted) > files_to_be_deleted
while read file
rm "$file"
done < files_to_be_deleted
PS:如果您希望将其另存为脚本并运行它,则可以使用来添加脚本名称echo scriptname >> not_to_be_deleted_files
。
尽管这不是必需的,但我更愿意这样做,因为以后不会后悔。我测试了一小组文件,它在我的系统中正常工作。但是,如果要确定,请先尝试在test
目录中,然后再删除原始目录中的文件。
我选择了一种更安全,更快得多的方法,因为列表中有18.000个文件!我需要在大型Drupal安装中清理映像。
删除所有不在列表中的文件与仅保留列表中的文件相同。因此,我决定实际将文件从列表复制到另一个位置,但是复制20 GB的文件将占用太多空间,并且速度也很慢。因此,诀窍是hardlinks
使用-l
选项来复制文件cp
。这几乎不占用空间并且非常快。另外,由于我需要保留目录结构,因此使用了该--parents
选项。
这是我的文件列表的摘录:
1px.png
misc/feed.png
modules/file/icons/x-office-presentation.png
modules/file/icons/x-office-spreadsheet.png
newsletter.png
sites/all/libraries/ckeditor/plugins/smiley/images/devil_smile.png
sites/all/libraries/ckeditor/plugins/smiley/images/regular_smile.png
sites/default/files/009313_PwC_banner_CBS_Observer_180x246px.jpg
因此,示例行将以temp为目的地:
cp -l --parents 'misc/feed.png' temp
这将创建以下结构:
temp
misc
feed.png
请注意,destinaton必须与硬链接的源位于同一文件系统中。
下一步是构建脚本:
sed -e "s,^,cp -l --parents '," -e "s,$,' /some/where/temp," filelist > newfilelist
现在,假设您已经创建了空目录/ some / where / temp,则可以复制以下文件:
sh newfilelist 2> missing_files
请注意错误如何最终以结束missing_files
。这种方法的额外好处是,您将从原始列表中获得实际上不存在的文件列表!
运行脚本后,temp将仅包含文件列表中的那些文件,但不删除任何内容且不占用额外空间。如果对结果满意,则可以删除所有原始文件,包括子文件夹。
最后,将文件和文件夹从temp移回原始位置。
对于18.000个文件,仅花费了几秒钟。