在命令行中排除 *

在命令行中排除 *

在很多情况下,使用*几乎是不可避免的 - 例如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'}这样吗?

答案1

对于 Bash,有一个名为的 shellextglob选项默认停用保持与标准 shell 语法的兼容性。外球通过附加运算符(例如!()、、等)补充语法。?()@()

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

对于 rm 示例:extglob您可以使用

rm -rf !(one|two|three)

答案2

我已经建造了除了正是为此(抱歉,我还不能添加文档)。

我有一个如下文件夹:

$ ls
a b c d

打字except b d会给ac

$ except b d
ac

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

except b d | xargs -0 rm

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

#!/usr/bin/env bash

except "$@" | xargs -0 rm

同样简单的是ls-except

#!/usr/bin/env bash

except "$@" | xargs -0 ls

答案3

作为 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' ./*

相关内容