从目录中删除除某些文件以外的所有文件


215

使用时sudo rm -r,如何删除所有文件,但以下情况除外:

textfile.txt
backup.tar.gz
script.php
database.sql
info.txt

5
听起来像是unix.stackexchange.com
Jason

1
有两种方法可以读取此问题,现有的答案涵盖两种解释:EITHER:(a)保存具有指定名称的文件,这些文件直接位于目标目录中,并且- rm -r暗示- 删除其他所有内容,包括子目录 -即使它们包含具有指定名称的文件;或:(b)遍历目标目录的整个子树,并在每个目录中删除所有文件(列出名称除外)。
mklement0 2014年

Answers:


219
find [path] -type f -not -name 'textfile.txt' -not -name 'backup.tar.gz' -delete

如果不指定,-type ffind还将列出您可能不需要的目录。


或更通用的解决方案,使用非常有用的组合find | xargs

find [path] -type f -not -name 'EXPR' -print0 | xargs -0 rm --

例如,删除当前目录中的所有非txt文件:

find . -type f -not -name '*txt' -print0 | xargs -0 rm --

print0-0是否有任何应该被删除的文件名的空间需要组合。


2
似乎xargs具有文字大小限制
frazras

26
删除多个模式:find . -type f -not -name '*ignore1' -not -name '*ignore2' | xargs rm
思思申申思维2013年

5
那目录呢?它将删除所有文件,但是会删除文件夹吗?
orezvani 2013年

31
find使用-delete参数代替“ | xargs rm”。
EmilStenström'13年

1
而不是-print0 | xargs -0 rm --您可以-delete
Andy

150
rm !(textfile.txt|backup.tar.gz|script.php|database.sql|info.txt)

需要在BASH中启用extglob(扩展模式匹配)(如果未启用):

shopt -s extglob

2
我这样做时会收到“意外标记'(')附近的语法错误shopt -s extglob; rm -rf !(README|LICENSE)。为什么知道吗?
Dennis

@nic我不记得了,对不起。我可能最终使用find了该-delete选项。
丹尼斯

这对我来说是最好的解决方案,默认情况下,它可以在我的Ubuntu 12.04.4 LTS上运行,而无需
购物

3
@nic,@Dennis:语法错误提示,其他的东西比bash被使用,例如dash,在extglob不支持。但是,在交互式 bash外壳程序中,该命令也将无法按所述方式运行,尽管原因有所不同。简而言之:shopt -s extglob由ITSELF 执行;一旦成功启用(用验证shopt extglob),请执行rm -rf !(README|LICENSE)。(虽然extglob尚未启用,但在执行命令之前!(...)历史扩展来评估;由于此操作可能失败,因此将执行extglob
NEITHER

2
@ nic,@ Dennis,@ mklement0:在.sh文件(#!/ bin / bash)中执行命令时,我遇到了与“意外令牌附近的语法错误”相同的问题,但是当我在命令中运行它时却没有事实证明,除了shopt -s extglob在命令行界面中运行外,我还必须在脚本文件中重新运行它
Ahresse

41

find . | grep -v "excluded files criteria" | xargs rm

这将列出当前目录中的所有文件,然后列出所有不符合您的条件的文件(请注意与目录名匹配的文件),然后将其删除。

更新:根据您的编辑,如果您确实要删除当前目录中除列出文件之外的所有内容,可以使用:

mkdir /tmp_backup && mv textfile.txt backup.tar.gz script.php database.sql info.txt /tmp_backup/ && rm -r && mv /tmp_backup/* . && rmdir /tmp_backup

它将创建一个备份目录/tmp_backup(您具有root权限,对吗?),将列出的文件移动到该目录,递归删除当前目录中的所有内容(您知道您在正确的目录中,对吗?),移动返回所有当前目录/tmp_backup,最后删除/tmp_backup

我选择备份目录位于根目录中,因为如果您尝试从根目录递归删除所有内容,则系统将遇到很大问题。

当然,有更优雅的方法可以做到这一点,但是这一方法非常简单。


2
与egrep一起使用也非常有效,例如用于清洁中间乳胶文件:find . | egrep -v "\.tex|\.bib" | xargs rm
mtsz 2013年

惊人的命令!删除目录只需更改为rm -r
Aris

1
如果您只想删除当前目录中除排除条件以外的所有内容:find . -maxdepth 1 | grep -v "exclude these" | xargs rm -r可以更快地工作,因为它不需要不必要地深入到目录。
billynoah 2014年

重新find流水线:除了效率问题(find单独使用3条命令),这对于带有嵌入式空格的文件名将无法正常工作,并且可能会删除错误的文件。
mklement0 2014年

如果将“要保存”的文件存储在另一个位置(/tmp_backup),则该命令如果中断就会无法正常工作-从用户的角度来看,所有文件都消失了,除非他们知道去哪里寻找它们以将其取回。因此,我不赞成这种策略。
Craig McQueen

20

假设具有这些名称的文件存在于目录树中的多个位置,并且您想保留所有这些文件:

find . -type f ! -regex ".*/\(textfile.txt\|backup.tar.gz\|script.php\|database.sql\|info.txt\)" -delete

19

您可以在Bash中使用GLOBIGNORE环境变量。

假设您要删除除php和sql之外的所有文件,则可以执行以下操作-

export GLOBIGNORE=*.php:*.sql
rm *
export GLOBIGNORE=

像这样设置GLOBIGNORE会忽略通配符(如“ ls *”或“ rm *”)中的php和sql。因此,在设置变量后使用“ rm *”将仅删除txt和tar.gz文件。


6
+1; 设置和恢复GLOBIGNORE变量的更简单替代方法是使用子外壳程序:(GLOBIGNORE='*.php:*.sql'; rm *)
mklement0 2014年

19

我更喜欢使用子查询列表:

rm -r `ls | grep -v "textfile.txt\|backup.tar.gz\|script.php\|database.sql\|info.txt"`

-v,--invert-match选择不匹配的行

\| 分隔器


1
优雅的解决方案
Joshua Salazar

9

由于没有人提到它:

  • 将您不想删除的文件复制到安全的地方
  • 删除所有文件
  • 将复制的文件移回原位

2
这更加复杂,因为将它们复制回之后,您必须注意权限。
罗慕路斯(Romulus)2014年

2
@RemusAvram您可以使用带有cprsync保留权限的适当开关。无论如何,这只是替代方法(作​​为建议),在此已作为OP的答案。
gniourf_gniourf 2014年

这在许多情况下可能不合适,在这些情况下,要保留的文件正被其他进程积极使用。也很麻烦,要删除的文件只是一小部分,并且涉及大量文件。
codeforester

@codeforester:可以。但是在某些情况下这是适当的,但是...实际上我看不到您的评论的重点:)
gniourf_gniourf

6

您可以为此编写一个for循环...%)

for x in *
do
        if [ "$x" != "exclude_criteria" ]
        then
                rm -f $x;
        fi
done;

6

对于OP来说有点晚了,但希望对后来被google赶到这里的人有用...

我发现@awi的答案和@Jamie Bullock对-delete的评论确实很有用。一个简单的实用程序,因此您可以在不同的目录中执行此操作,而每次输入时只需使用最少的输入即可忽略不同的文件名/类型:

rm_except(或任何您想命名的名称)

#!/bin/bash

ignore=""

for fignore in "$@"; do
  ignore=${ignore}"-not -name ${fignore} "
done

find . -type f $ignore -delete

例如删除除文本文件和foo.bar之外的所有内容:

rm_except *.txt foo.bar 

类似于@mishunika,但没有if子句。


5

如果您使用的zsh是我强烈推荐的方式。

rm -rf ^file/folder pattern to avoid

extended_glob

setopt extended_glob
rm -- ^*.txt
rm -- ^*.(sql|txt)

4

尝试使用:

rm -r !(Applications|"Virtualbox VMs"|Downloads|Documents|Desktop|Public)

但是带有空格的名称(一如既往)很难。也尝试使用Virtualbox\ VMs引号。它总是删除该目录(Virtualbox VMs)。


不适用于文件。rm !(myfile.txt)删除所有包括myfile.txt
khaverim

应该shopt -s extglob首先执行@ pl1nk指出的
-zhuguowei

是的,激活bash中的扩展glob(extglob)非常重要,我每天在实验室中的几台Mac电脑上进行此操作: shopt -s extglob然后cd /Users/alumno/最终在此处rm -rf !(Applications|Virtualbox*VMs|Downloads|Documents|Desktop|Public|Library) 了解有关扩展glob的信息
juanfal

4

只是:

rm $(ls -I "*.txt" ) #Deletes file type except *.txt

要么:

rm $(ls -I "*.txt" -I "*.pdf" ) #Deletes file types except *.txt & *.pdf

不建议这样做。解析ls输出可能成为一个问题。有关详细信息,请参见此处
RJ

2

使文件不可变。甚至不允许root用户删除它们。

chattr +i textfile.txt backup.tar.gz script.php database.sql info.txt
rm *

所有其他文件已被删除。
最终,您可以将它们重置为可变的。

chattr -i *

0

这类似于@ siwei-shen的评论,但是您需要-o标记来执行多种模式。该-o标志代表“或”

find . -type f -not -name '*ignore1' -o -not -name '*ignore2' | xargs rm


0

您可以使用两个命令序列来执行此操作。首先用您不想排除的文件名定义一个数组:

files=( backup.tar.gz script.php database.sql info.txt )

之后,遍历您要排除的目录中的所有文件,检查文件名是否在您不想排除的数组中;如果不是,则删除文件。

for file in *; do
  if [[ ! " ${files[@]} " ~= "$file"  ]];then
    rm "$file"
  fi
done

正则表达式比较不正确-它将保留名称是其中一个受保护文件的子字符串的任何文件(尽管周围的空格在某种程度上可以缓解这种情况;但是文件名可以包含空格)。您应该收集所有文件的数组,然后从该数组中减去要排除的文件,然后删除其余文件。
Tripleee '18

-1

由于尚无人提及,因此在一种特定情况下:

OLD_FILES=`echo *`
... create new files ...
rm -r $OLD_FILES

(或只是rm $OLD_FILES

要么

OLD_FILES=`ls *`
... create new files ...
rm -r $OLD_FILES

shopt -s nullglob如果某些文件可能存在或不存在,则可能需要使用:

SET_OLD_NULLGLOB=`shopt -p nullglob`
shopt -s nullglob
FILES=`echo *.sh *.bash`
$SET_OLD_NULLGLOB

没有nullglob, echo *.sh *.bash可能会给您“ a.sh b.sh * .bash”。

(说了这么多,我自己更喜欢这个答案,即使它在OSX中不起作用)


Leonardo Hermoso的现有答案可以减少错误。对于带空格的文件名,此操作将失败;使用数组可以很好地解决该特定问题(也不太重要地避免将大写用作其私有变量,通常应避免使用大写)。
三人房

-3

与其直接发送命令,不如将所需文件移至当前目录之外的temp目录。然后使用rm *或删除所有文件rm -r *

然后将所需文件移到当前目录。


这在许多情况下可能不合适,在这些情况下,要保留的文件正被其他进程积极使用。也很麻烦,要删除的文件只是一小部分,涉及大量文件。
codeforester

-3

删除所有不包括file.name的内容:

ls -d /path/to/your/files/* |grep -v file.name|xargs rm -rf

2
如果您的目录/文件包含空格或不寻常的字符,这将严重失败,并可能导致数据丢失。您不应该解析ls。mywiki.wooledge.org/ParsingLs
RJ
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.