删除目录中名称与文件列表中的行不匹配的所有文件

删除目录中名称与文件列表中的行不匹配的所有文件

我有一个包含 1000 多个文件的目录。在一个文本文件中,我有大约 50 个文件名,每行一个。我想删除目录中文件名与列表中的条目不对应的所有文件。最好的方法是什么?我启动了一个 shell 脚本,但无法确定正确的命令来确定文件名是否在列表中。谢谢。

答案1

我意识到任何询问如何删除文件的问题都必须非常小心。我的第一个答案太仓促了,我没有考虑到文件列表可能格式错误而无法与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吸收了所有的流。我添加了一个命令,在每个文件名周围放置“^”和“$”。我很幸运,内森的文件列表是正确的。如果是使用 CR-LF 结束行或附加空格的 DOS 格式,egrep 不会保留任何文件,并且所有文件都会被删除。

答案2

预先构造以下参数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"

答案3

zsh

mylist=(${(f)"$(<filelist)"})
print -rl -- *(.^e_'(($mylist[(Ie)$REPLY]))'_)

filelist它读取数组中的行,然后使用全局限定符/e字符串仅全局/选择数组中不存在的文件名:.仅选择常规文件(D如果列表包含点文件则添加),而否定^e_'expression'_进一步仅选择表达式返回 false 的文件,即如果它们的名称 ( $REPLY)不是数组的元素
如果您对结果满意,请替换print -rlrm以实际删除文件:

rm -- *(.^e_'(($mylist[(Ie)$REPLY]))'_)

要递归选择和删除文件,请使用*/**glob${REPLY:t}全局修饰符:

rm -- */**(.^e_'(($mylist[(Ie)${REPLY:t}]))'_)

答案4

运行以下脚本。

  1. 最初,我查找目录中存在的所有文件并将输出存储到另一个文件中all_files
  2. 我们有一个文件,其中包含应该的文件列表不是删除( not_to_be_deleted_files)。
  3. 我将文件名添加到的末尾,not_to_be_deleted_files因为 我们需要这两个文件。files_to_be_deletednot_to_be_deleted_files
  4. 现在,我正在使用 linux 命令查找需要删除的文件 join并将输出重定向到files_to_be_deleted 文件。
  5. 现在,在最后一个 while 循环中,我正在读取其中的所有文件名 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

聚苯乙烯:也许,如果您希望将其保存为脚本并运行它,您也可以使用 . 添加脚本名称echo scriptname >> not_to_be_deleted_files

虽然这不是必需的,但我更愿意这样做,因为以后就不会后悔了。我测试了一小组文件,它在我的系统中工作。但是,如果您想确定,请先在一个test目录中尝试,然后删除原始目录中的文件。

相关内容