401

I have a directory containing a large number of files. I want to delete all files except for file.txt . How do I do this?

There are too many files to remove the unwanted ones individually and their names are too diverse to use * to remove them all except this one file.

Someone suggested using

rm !(file.txt)

But it doesn't work. It returns:

Badly placed ()'s 

My OS is Scientific Linux 6.

Any ideas?

8个答案   正确答案

445

POSIXly:

find . ! -name 'file.txt' -type f -exec rm -f {} +

将删除除file.txt要删除目录,请更改-type f-type d并添加-r选项rm

bash, 要使用rm -- !(file.txt), 您必须启用 extglob :

$ shopt -s extglob 
$ rm -- !(file.txt)

(或打电话bash -O extglob

请注意,它extglob仅适用于bashKorn shell 系列。并且使用rm -- !(file.txt)会导致Argument list too long错误。

在 中zsh,您可以在启用extendedglob^的情况下使用否定模式

$ setopt extendedglob
$ rm -- ^file.txt

或者使用相同的语法和ksh选项bashksh_glob启用no_bare_glob_qual

184

另一个采取不同的方向(如果文件名中没有空格)

ls | grep -xv "file.txt" | xargs rm

或(即使文件名中有空格也能工作)

ls | grep -xv "file.txt" | parallel rm

来自man grep:

 -v, --invert-match
          Invert the sense of matching, to select non-matching lines.  (-v is specified by POSIX)

 
 -x, --line-regexp
          Select  only  those  matches  that exactly match the
          whole line.  For a regular expression pattern,  this
          is   like   parenthesizing   the  pattern  and  then
          surrounding it with ^ and $.

没有我们也会-x保留。my-file.txt

47
+50

维护一个副本,删除所有内容,恢复副本:

{   rm -rf *
    tar -x
} <<TAR
$(tar -c $one_file)
TAR

在一行中:

{ rm -rf *; tar -x; } <<< $(tar -c $one_file)

但这需要一个支持 here-strings 的 shell。

  • 25
    这有点令人兴奋。 
    – vschum
     2014 年 9 月 5 日 2:36
  • 2个
    但是,如果中途中断,或者出现其他任何问题,文件就会丢失。 
    – kasperd
     2014 年 9 月 5 日 8:04
  • 3个
    把它移到另一个目录再移回来不是更有效率吗?我们不需要处理文件的内容,只需要处理它的路径。  2014 年 9 月 6 日 15:51
  • 3个
    @Derek - 真的没那么疯狂。POSIX 要求 shell 在遇到 here-document 时将其输入重定向到您指定的命令。命令替换必须在其他任何事情发生之前完成。大多数 shell 将临时文件用于 here-docs - 一些管道。无论哪种方式tar -c完成,shell 都会在rm运行前存储其输出。因为在完成rm忽略了stdin它的左挂- 并且 shell 可以剥离它保存的文件副本。Here-docs 很多时候可以像瞄准管道一样使用。tar -xrm  2014 年 9 月 9 日 5:27 
  • 5个
    如果文件大小为 64GB 怎么办?还是不涉及实际复制?  2018 年 7 月 13 日 19:04 
37

你们都想多了。

cd ..
mv fulldir/file.txt /tmp/
rm -rf fulldir
mkdir fulldir
mv /tmp/file.txt fulldir/

完毕。

编辑实际上,更容易:

cd ..
ln fulldir/file.txt ./
rm -rf fulldir
mkdir -p fulldir
mv file.txt fulldir/
  • 5个
    这和我的回答是一样的。exce[pt 它不会失去对目录的任何权限。  2014 年 9 月 5 日 12:50 
  • 9
    如果它是与 /tmp 不同的文件系统上的一个大文件,并且您正试图从文件系统的根目录中删除所有内容,那么将它移动到安全的地方可能不是一种选择。  2014 年 9 月 6 日 5:24
  • 3个
    这绝对是最简单的答案。  2016 年 10 月 18 日 23:10
  • 1个
    fulldir如果是挂载点,两者都会失败。fulldir如果不是具有标准权限的“您的”目录,两者都会导致不正确的设置  2020 年 7 月 4 日 10:50
  • 1个
    另外,我想知道那里是否有人知道如何保留目录权限。感觉必须有办法。无论哪种方式,在mv目录外读取文件,然后以某种方式删除内容,似乎是最好、最安全、最明显的方法。也许这个 StackExchange 上的每个人都非常擅长 shell 脚本。  2021 年 6 月 20 日 22:08
25

在我的 Scientific Linux 6 操作系统上,这有效:

shopt -s extglob
rm !(file.txt)

我还在虚拟机上安装了 Debian 32bit。以上不起作用,但以下起作用:

find . -type f ! -name 'file.txt' -delete
12

我发现这种方法非常简单、有效,并且不需要任何特殊扩展(据我所知!)

ls --hide=file.txt | xargs -d '\n' rm
11

使用rm !("file.txt")而不是rm !(file.txt)

  • 13
    这绝对没有任何区别。这里的问题是 OP 是 1) 没有使用支持这种格式的 shell 和 2) 即使在 bash 中,你也需要使用shopt -s extglob无论如何,引用一个像这样的简单文件名不会有任何区别。 
    – 特顿
     2014 年 9 月 6 日 11:15
  • 1个
    要只保留 utils 文件夹,请执行 - rm -rf !("utils")  2018 年 2 月 1 日 18:27
8个

rm只是为了给出不同的答案,您可以使用它不会删除文件夹的默认行为:

mkdir tmp && mv file.txt tmp  # create tmp dir and move files there
rm                            # delete all other files
mv tmp/* . && rm -rf tmp      # move all files back and delete tmp dir
  • 如果 ./tmp 已经作为一个文件存在,或者更糟的是,作为一个已经包含内容的目录,这会发生什么?使用dirr=mktemp && mv file.txt "$dirr"; rm; mv "$dirr/*" . && rm -rf "$dirr"可以避免这个问题。 
    – 
     2020 年 1 月 26 日 13:52

不是您要找的答案?浏览其他标记的问题或者问你自己的问题


来自  https://unix.stackexchange.com/questions/153862/remove-all-files-directories-except-for-one-file