简体   繁体   English

Unix:如何删除文件中列出的文件

[英]Unix: How to delete files listed in a file

I have a long text file with list of file masks I want to delete我有一个长文本文件,其中包含要删除的文件掩码列表

Example:例子:

/tmp/aaa.jpg
/var/www1/*
/var/www/qwerty.php

I need delete them.我需要删除它们。 Tried rm `cat 1.txt` and it says the list is too long.试过 rm `cat 1.txt`,它说列表太长。

Found this command, but when I check folders from the list, some of them still have files xargs rm <1.txt Manual rm call removes files from such folders, so no issue with permissions.找到了这个命令,但是当我从列表中检查文件夹时,其中一些文件夹仍然有文件xargs rm <1.txt Manual rm call 从这些文件夹中删除文件,所以权限没有问题。

This is not very efficient, but will work if you need glob patterns (as in /var/www/*)这不是很有效,但如果您需要 glob 模式(如 /var/www/*)

for f in $(cat 1.txt) ; do 
  rm "$f"
done

If you don't have any patterns and are sure your paths in the file do not contain whitespaces or other weird things, you can use xargs like so:如果您没有任何模式并且确定文件中的路径不包含空格或其他奇怪的东西,您可以像这样使用 xargs:

xargs rm < 1.txt

Assuming that the list of files is in the file 1.txt , then do:假设文件列表在文件1.txt ,然后执行:

xargs rm -r <1.txt

The -r option causes recursion into any directories named in 1.txt . -r选项导致递归到1.txt命名的任何目录。

If any files are read-only, use the -f option to force the deletion:如果任何文件是只读的,请使用-f选项强制删除:

xargs rm -rf <1.txt

Be cautious with input to any tool that does programmatic deletions.任何执行程序化删除的工具的输入要谨慎。 Make certain that the files named in the input file are really to be deleted.确保在输入文件中指定的文件是真的被删除。 Be especially careful about seemingly simple typos.要特别小心看似简单的错别字。 For example, if you enter a space between a file and its suffix, it will appear to be two separate file names:例如,如果在文件及其后缀之间输入一个空格,它将显示为两个单独的文件名:

file .txt

is actually two separate files: file and .txt .实际上是两个单独的文件: file.txt

This may not seem so dangerous, but if the typo is something like this:这可能看起来并不那么危险,但如果拼写错误是这样的:

myoldfiles *

Then instead of deleting all files that begin with myoldfiles , you'll end up deleting myoldfiles and all non-dot-files and directories in the current directory.然后,不是删除所有以myoldfiles开头的文件,您最终将删除当前目录中的myoldfiles所有非点文件和目录。 Probably not what you wanted.可能不是你想要的。

Use this:用这个:

while IFS= read -r file ; do rm -- "$file" ; done < delete.list

If you need glob expansion you can omit quoting $file :如果您需要 glob 扩展,您可以省略引用$file

IFS=""
while read -r file ; do rm -- $file ; done < delete.list

But be warned that file names can contain "problematic" content and I would use the unquoted version.但请注意,文件名可能包含“有问题”的内容,我将使用未引用的版本。 Imagine this pattern in the file想象一下文件中的这种模式

*
*/*
*/*/*

This would delete quite a lot from the current directory!这将从当前目录中删除很多! I would encourage you to prepare the delete list in a way that glob patterns aren't required anymore, and then use quoting like in my first example.我鼓励您以不再需要 glob 模式的方式准备删除列表,然后像我的第一个示例一样使用引用

You could use '\\n' for define the new line character as delimiter.您可以使用 '\\n' 将换行符定义为分隔符。

xargs -d '\n' rm < 1.txt

Be careful with the -rf because it can delete what you don't want to if the 1.txt contains paths with spaces.小心 -rf 因为如果 1.txt 包含带空格的路径,它可以删除您不想要的内容。 That's why the new line delimiter a bit safer.这就是为什么新的行分隔符更安全的原因。

On BSD systems, you could use -0 option to use new line characters as delimiter like this:在 BSD 系统上,您可以使用 -0 选项来使用换行符作为分隔符,如下所示:

xargs -0 rm < 1.txt

xargs -I{} sh -c 'rm "{}"' < 1.txt should do what you want. xargs -I{} sh -c 'rm "{}"' < 1.txt应该做你想做的。 Be careful with this command as one incorrect entry in that file could cause a lot of trouble.小心使用此命令,因为该文件中的一个错误条目可能会导致很多麻烦。

This answer was edited after @tdavies pointed out that the original did not do shell expansion.这个答案是在@tdavies 指出原文没有做 shell 扩展之后被编辑的。

You can use this one-liner:你可以使用这个单线:

cat 1.txt | xargs echo rm | sh

Which does shell expansion but executes rm the minimum number of times.它进行外壳扩展但执行rm的次数最少。

Just to provide an another way, you can also simply use the following command只是提供另一种方式,您也可以简单地使用以下命令

$ cat to_remove
/tmp/file1
/tmp/file2
/tmp/file3
$ rm $( cat to_remove )

In this particular case, due to the dangers cited in other answers, I would在这种特殊情况下,由于其他答案中引用的危险,我会

  1. Edit in eg Vim and :%s/\\s/\\\\\\0/g , escaping all space characters with a backslash.在例如 Vim 和:%s/\\s/\\\\\\0/g ,用反斜杠转义所有空格字符。

  2. Then :%s/^/rm -rf / , prepending the command.然后:%s/^/rm -rf / ,在命令前面。 With -r you don't have to worry to have directories listed after the files contained therein, and with -f it won't complain due to missing files or duplicate entries.使用-r您不必担心在其中包含的文件之后列出目录,而使用-f它不会因丢失文件或重复条目而抱怨。

  3. Run all the commands: $ source 1.txt运行所有命令: $ source 1.txt

cat 1.txt | xargs rm -f | bash cat 1.txt | xargs rm -f | bash Run the command will do the following for files only. cat 1.txt | xargs rm -f | bash运行该命令将仅对文件执行以下操作。

cat 1.txt | xargs rm -rf | bash cat 1.txt | xargs rm -rf | bash Run the command will do the following recursive behaviour. cat 1.txt | xargs rm -rf | bash运行该命令将执行以下递归行为。

Here's another looping example.这是另一个循环示例。 This one also contains an 'if-statement' as an example of checking to see if the entry is a 'file' (or a 'directory' for example):这个还包含一个“if-statement”作为检查条目是否为“文件”(或例如“目录”)的示例:

for f in $(cat 1.txt); do if [ -f $f ]; then rm $f; fi; done

Here you can use set of folders from deletelist.txt while avoiding some patterns as well在这里,您可以使用deletelist.txt 中的文件夹集,同时避免某些模式

foreach f (cat deletelist.txt)
    rm -rf ls | egrep -v "needthisfile|*.cpp|*.h"
end

This will allow file names to have spaces (reproducible example).这将允许文件名包含空格(可重现的示例)。

# Select files of interest, here, only text files for ex.
find -type f -exec file {} \; > findresult.txt
grep ": ASCII text$" findresult.txt > textfiles.txt
# leave only the path to the file removing suffix and prefix
sed -i -e 's/:.*$//' textfiles.txt
sed -i -e 's/\.\///' textfiles.txt

#write a script that deletes the files in textfiles.txt
IFS_backup=$IFS
IFS=$(echo "\n\b")
for f in $(cat textfiles.txt); 
do 
rm "$f"; 
done
IFS=$IFS_backup

# save script as "some.sh" and run: sh some.sh

In case somebody prefers sed and removing without wildcard expansion :如果有人更喜欢sed和 remove没有通配符扩展

sed -e "s/^\(.*\)$/rm -f -- \'\1\'/" deletelist.txt | /bin/sh

Reminder: use absolute pathnames in the file or make sure you are in the right directory.提醒:在文件中使用绝对路径名或确保您位于正确的目录中。

And for completeness the same with awk :为了完整性,与awk相同:

awk '{printf "rm -f -- '\''%s'\''\n",$1}' deletelist.txt | /bin/sh

Wildcard expansion will work if the single quotes are remove, but this is dangerous in case the filename contains spaces.如果删除单引号,通配符扩展将起作用,但如果文件名包含空格,则这是危险的。 This would need to add quotes around the wildcards.这需要在通配符周围添加引号。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM