在命令行中从*排除


14

在很多情况下,*实际上不可避免地会使用a-例如,rm -rf *在包含数千个子文件夹和文件的文件夹中。

但是,如果您只想从rm命令中排除一个或两个文件或文件夹,该怎么办?我GOOGLE了我的路周围,才发现好像挺复杂的解决方案,find . -depth -not \( -name 'one' -o -name 'two' \ -o -name 'three' \) -exec rm {} \;如规定在这里

有没有可能以更简单的方式做到这一点-而不走弯路find?例如rm -rf --exclude='one' --exclude='two' --exclude='three' *喜欢在rsync还是rm -rf -e 'one','two','three' *

甚至一般的可能性排除的东西*(所以其他命令一样cpmv...没有实现自己的)?大概是*{'one','two','three'}什么?


3
如果只想保留一个或两个文件,那么最简单,最简单的方法就是将这些文件移动到另一个位置,擦除所有剩余的文件,然后将保留的文件移回。如果您想保留更多文件,则可以使用find--delete选项(无需rm为每个文件执行。这是不必要的开销)。
Hennes

那是可能的,但是几乎和我提到的一样详尽。我知道我可以将命令组合到类似的东西上mv -t /tmp one two three && rm -rf * && mv -t . /tmp/one /tmp/two /tmp/three,但是我更希望有一个解决方案,它可以明确地从*。肯定会有无法将文件移动或复制到另一个目标的情况。
大卫,

2
这就是为什么我没有将其发布为答案。只是作为一种不太复杂的处理方式(三个非常简单的命令与一个稍微复杂一些的命令)。我讨厌与RM相结合的复杂性。
亨尼斯,2013年

Answers:


33

对于Bash,有一个名为shell的选项,默认情况下extglob停用,以保持与标准Shell语法的兼容性。Extglob通过附加的运算符!()?()@()以及其他)补充语法。

要打开extglob,请键入shopt -s extglob。要针对当前用户类型保持打开状态echo 'shopt -s extglob' >> ~/.bashrc

对于rm示例:extglob可以使用

rm -rf !(one|two|three)

似乎是一个很好的解决方案,但我也不想每次遇到上述情况时都将其打开和关闭。
大卫,

3
@David:你可以把shopt东西放进去~/.bashrc,不会伤到你。
enzotib

如果我做对了,extglob选项根本不会改变效果*,而是会添加!具有其他功能的类似指示器(如)?在这种情况下,这将是一个不错的解决方案。
大卫,

1
@David:是的。
choroba

1
@David 保持与标准Shell语法的兼容性。在其他情况下,行为可能会发生变化。
gerrit 2013年

4

除此以外,我已经构建了(抱歉,我还无法添加文档)。

我有一个类似以下的文件夹:

$ ls
a b c d

打字except b d会给你ac

$ except b d
ac

现在,您可以将其通过管道传输到rm

except b d | xargs -0 rm

这可能很难记住,所以为什么不只是在除外之上构建一个脚本,称为 rm-except

#!/usr/bin/env bash

except "$@" | xargs -0 rm

同样容易的是ls-except

#!/usr/bin/env bash

except "$@" | xargs -0 ls

3
这很好,但是当您了解extglob时并不需要它-askubuntu.com/a/329233/138369
David

1

作为extglob的替代方法(尽管这是一个很好的答案,每个人都应shopt -s extglob globstar在.bashrc中使用它),可以使用$ GLOBIGNORE全局变量。假设您要获取除“ foo.txt”和“ bar baz.txt”以外的所有文件:

GLOBIGNORE=foo.txt:'bar baz.txt'

...但是,这将打开shell选项dotglob,这意味着*将匹配以点(通常是隐藏的)开头的文件。因此,您实际上需要两个命令:

GLOBIGNORE=foo.txt:'bar baz.txt'
shopt -u dotglob

由于这是一个全局变量,它将影响您使用的每个glob,直到通过注销或通过以下方式取消设置$ GLOBSTAR为止

GLOBIGNORE=

它也仅适用于传递给变量的文字字符串。您可以通过设置$ GLOBIGNORE并查看这些命令之间的区别来理解我的意思:

printf '%s\n' *
printf '%s\n' ./*
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.