删除除一个文件外的所有文件/目录

Kan*_*ura 344 file-management

我有一个包含大量文件的目录。我想删除除 file.txt 之外的所有文件。我该怎么做呢?

有太多文件无法单独删除不需要的文件,而且它们的名称过于多样化,无法使用 * 将它们全部删除,除了这个文件。

有人建议使用

rm !(file.txt)
Run Code Online (Sandbox Code Playgroud)

但它不起作用。它返回:

Badly placed ()'s 
Run Code Online (Sandbox Code Playgroud)

我的操作系统是 Scientific Linux 6。

有任何想法吗?

cuo*_*glm 385

POSIXly:

find . ! -name 'file.txt' -type f -exec rm -f {} +
Run Code Online (Sandbox Code Playgroud)

将删除所有常规文件(递归,包括隐藏文件),除了file.txt. 要删除目录,请更改-type f-type d并将-r选项添加到rm.

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

$ shopt -s extglob 
$ rm -- !(file.txt)
Run Code Online (Sandbox Code Playgroud)

(或打电话bash -O extglob

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

在 中zsh,您可以使用启用extendedglob^来否定模式:

$ setopt extendedglob
$ rm -- ^file.txt
Run Code Online (Sandbox Code Playgroud)

或使用相同的语法kshbash选项ksh_globno_bare_glob_qual启用。

  • 指定目录是一种很好的做法(在这种情况下是完整路径?或者可能在此处添加警告,该命令会删除*从当前工作目录*开始的每个文件?)。我也通常将任何带有 `rm` 的例子写成 `echo rm`,并要求人们只在他们真正确定它会做他们想要的时才取出回声。除此之外,对于彻底的答案+1 (14认同)
  • 我建议使用 `-delete` 而不是 `-exec`,更短更容易记住 (13认同)
  • @Izkata:`-delete` 不是由 POSIX 定义的。 (9认同)
  • 如何排除文件列表? (6认同)
  • @Meysam - 有关将处理文件列表的解决方案,请参阅我的答案。否则,您可以使用 Gnouc 的 `find` 解决方案`!\( -name one_file -o -name two_file \)` 等等。 (5认同)
  • @cuonglm,如果有人解释一下为什么最后有“+”,那就更好了,因为我经常看到“;” (3认同)
  • 如果你使用 `rm -r`,你将删除包含 `file.txt` 的目录,这将有效地删除你想要保留的文件。 (2认同)
  • 如果没有与子文件位于同一级别的目录,则 `rm !(file.txt)` 工作正常,`rm -rf !(file.tx)` 将解决此问题 (2认同)
  • 要使用“find”删除目录,请将“rm”更改为“rmdir”,而不是“rm -r”。`rmdir` 不会删除包含文件的目录,而 `rm -r` 会删除(从而删除 `file.txt`)。**如果**您使用的是 GNU `rmdir`,您还可以使用它的 `--ignore-fail-on-non-empty` 选项。 (2认同)
  • 我必须使用 `find 。!-name 'basejit-cli.sh' !-姓名 '。' !-name '..' -exec rm -rf {} +` 以避免尝试在 macOS 上删除 `.` 和 `..`。 (2认同)

Seb*_*ian 164

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

ls | grep -v file.txt | xargs rm
Run Code Online (Sandbox Code Playgroud)

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

ls | grep -v file.txt | parallel rm
Run Code Online (Sandbox Code Playgroud)

来自man grep

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

  • 这对我有用`ls -Q | grep -v 文件.txt | xargs rm -fr` 。-Q 开关是“将条目名称括在双引号中” (14认同)
  • 如果文件名有空格,它将不起作用...... (4认同)
  • 它不仅是空格,都是空格和换行符,还包括引号字符(单引号、双引号和反斜杠)和以 `-` 开头的文件名。 (3认同)
  • Ciao @Matteo,它也适用于带有空格的文件,但是您需要用引号将 grep 模式括起来,例如`ls | grep -v "带有空格的文件.bin" | xargs rm`。这是正常的 `grep` 语法。 (2认同)
  • @Sebastian 问题不在于 `grep`,而是 `rm`。`rm` 会得到一个空格分隔的参数列表。尝试`触摸'a b'; 触摸“c d”;ls | grep -v 'ab' | xargs rm`: 你会得到 `rm: c: No such file or directory` 和 `rm: d: No such file or directory` (2认同)
  • @kuzyn:哇,你每天都学到新东西。好的 (2认同)
  • 如果没有像“file\.txt”那样转义以仅匹配文字点,则“grep”搜索模式中的点字符将匹配任何字符。例如,它还将匹配名为“filestxt”的文件。 (2认同)

mik*_*erv 42

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

{   rm -rf *
    tar -x
} <<TAR
$(tar -c $one_file)
TAR
Run Code Online (Sandbox Code Playgroud)

在一行中:

{ rm -rf *; tar -x; } <<< $(tar -c $one_file)
Run Code Online (Sandbox Code Playgroud)

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

  • 这有点令人兴奋。 (18认同)
  • 将其移动到另一个目录并将其移回不是更有效吗?我们不需要处理文件的内容,只需要处理它的路径。 (3认同)
  • @Derek - 真的没那么疯狂。POSIX 要求 shell 在遇到 here-document 时将其输入重定向到您指定的命令。命令替换必须在其他任何事情发生之前完成。大多数 shell 将临时文件用于 here-docs - 一些管道。无论哪种方式,`tar -c` 都会完成,并且 shell 会在 `rm` 运行之前隐藏其输出。因为`rm` 忽略`stdin`,它在`rm` 完成时为`tar -x` 留下了挂起——并且shell 可以剥离它保存的文件副本。很多时候,Here-docs 可以像瞄准管道一样使用。 (3认同)
  • 如果文件大小为 64GB 怎么办?还是不涉及实际复制? (3认同)
  • @Derek - 请参阅编辑。 (2认同)
  • 但是,如果这在中途被中断,或者如果出现任何其他问题,文件就会消失。 (2认同)
  • @kasperd - 不。仅当父 shell 在它运行 `rm` 和 `tar -x` 之间死亡时。`rm` 可以随心所欲地失败。 (2认同)
  • @leonboy - 可能,但如果你跨越文件系统,那没有什么区别 (2认同)
  • 刚刚看到你的单行版本 @mikeserv ,哇,虽然它有点超出我的头脑,但我试过了,它确实有效。 (2认同)
  • 这仅适用于“zsh”,因为 tar 的输出通常包含 NUL 字节。即使如此,对于内容以空行结尾并与 tar 块大小对齐的文件,您也会遇到麻烦。 (2认同)
  • @Zimano 最好的猜测是,它会将文件读入内存,并将其作为新文件写回。我希望这对硬件来说比根本不接触文件或只是在现代文件系统上“移动”文件更困难 (2认同)
  • @thorsummoner 是的。我听说过想法。我认为它们是这样的,但我以前错了! (2认同)

Sha*_*dur 33

你们都想多了。

cd ..
mv fulldir/file.txt /tmp/
rm -rf fulldir
mkdir fulldir
mv /tmp/file.txt fulldir/
Run Code Online (Sandbox Code Playgroud)

完毕。

编辑实际上,更容易:

cd ..
ln fulldir/file.txt ./
rm -rf fulldir
mkdir -p fulldir
mv file.txt fulldir/
Run Code Online (Sandbox Code Playgroud)

  • 如果它是与 /tmp 分开的文件系统上的一个大文件,并且您试图从文件系统的根目录下删除所有内容,那么将它移到安全的地方可能不是一个选择。 (7认同)
  • 这和我的回答是一样的。例外[pt 它不会失去对目录的任何权限。 (5认同)
  • 这绝对是最简单的答案。 (2认同)

Kan*_*ura 21

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

shopt -s extglob
rm !(file.txt)
Run Code Online (Sandbox Code Playgroud)

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

find . -type f ! -name 'file.txt' -delete
Run Code Online (Sandbox Code Playgroud)


小智 12

使用rm !("file.txt")代替rm !(file.txt)

  • 这绝对没有任何区别。这里的问题是 OP 1) 不使用支持这种格式的 shell 和 2) 即使在 bash 中,您也需要使用 `shopt -s extglob` 启用它。在任何情况下,引用这样的简单文件名都没有区别。 (8认同)

Nit*_*hin 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
Run Code Online (Sandbox Code Playgroud)


2-b*_*its 6

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

ls --hide=file.txt | xargs -d '\n' rm
Run Code Online (Sandbox Code Playgroud)

  • 这只是网络笑话,当您重新访问您已经完成的搜索并回来回答您已经投票时。 (2认同)