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


9

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

Answers:


8

我意识到,任何询问如何删除文件的问题都必须格外小心。我的第一个答案太草率了,我没有想到文件列表可能格式错误,无法与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不会保留任何文件,而所有文件都将被删除。


当我运行预览命令时,我得到一行“ rm”。当我运行实际命令时,我收到一条有关缺少rm参数的错误消息。我需要特殊的语法来使用ls的结果吗?在xargs输入中使用egrep?
内森2014年

@Nathan,您必须首先CD到目录。没有特殊的语法。ls提供目录文件名,egrep -vf filelist过滤您的50个文件名。恐怕您删除了所有文件。
伊曼纽尔2014年

@Emamanuel我正在从包含要删除文件的目录中运行命令。
内森

@Nathan是否删除了所有文件?
伊曼纽尔

不,他们仍然在那里。
内森2014年

1

将参数预先构造为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"

我最喜欢这一点,因为它消除了需要的文件列表
eyoung100

从我那里+1,尽管它不能很好地处理空格。也许'应该添加一些单引号()即keep=( -name \'"$REPLY"\' )keep+=( -o -name \'"$REPLY"\' )
Cristian Ciupitu 2014年

上面的操作很危险,因为您可能会意外删除文件。
davidva

@CristianCiupitu不是吗?我添加了一个演示,演示了它与空白的关系非常好。
kojiro 2014年

@davidva在什么情况下?每当您自动删除内容时,都会冒犯错误的风险,但是在问题的参数范围内,我认为我的演示证明了这种方法是正确的。
kojiro 2014年

1

zsh

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

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

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

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

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

0

如果将目录的内容放入如下文件中:

cd <somedirectory>
ls >> filelist

用文本编辑器打开文件列表,并删除除了那些所有文件要删除。之所以加粗,是因为与上述答案相反

尝试这个:

while read p || [[ -n $p ]]; 
echo $p
done < filelist

如果您看到输出到屏幕的文件列表,则将echo替换为rm -v,如下所示:

while read p || [[ -n $p ]]; 
rm -v $p
done < filelist

0

运行以下脚本。

  1. 最初,我要查找目录中存在的所有文件,并将输出存储到另一个文件中all_files
  2. 我们其中有应的文件列表中的文件被删除(not_to_be_deleted_files)。
  3. 我加入的文件名not_to_be_deleted_files,并 files_to_be_deleted在2002年底not_to_be_deleted_files,我们需要这2个文件。
  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

PS:如果您希望将其另存为脚本并运行它,则可以使用来添加脚本名称echo scriptname >> not_to_be_deleted_files

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


0
  • 使用列表作为源,将列表中的所有文件移动到新的,空的保存目录中。
  • 比较列表中的文件数和已保存的文件数。
  • 如果两者都匹配,请使用您喜欢的方法删除所有未保存的文件。
  • 移回保存的文件。

0

我选择了一种更安全,更快得多的方法,因为列表中有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个文件,仅花费了几秒钟。


0

安全,简单。

cd 到目录。

创建一个临时目录。

mv *.yourExlusionSelector.* ./temp
rm *
mv ./temp ./
rm -rf ./temp

完成。


欢迎来到该网站。如果OP提到的列表中的名称是简单的模式匹配的结果,则您的方法会起作用-这种情况很可能会发生-但请注意,OP声明要排除的文件名存储在特定文件中;您可能需要扩展答案,以便从该文件中读取排除模式,而不是依靠一个静态模式,或者必须将可能多个模式键入到控制台。
AdminBee
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.