在很多情况下,使用*
几乎是不可避免的 - 例如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' *
?
也许甚至可以将某些东西排除在外*
(这样其他命令如cp
、mv
、 ... 就不必自己实现)?类似*{'one','two','three'}
这样吗?
答案1
答案2
我已经建造了除了正是为此(抱歉,我还不能添加文档)。
我有一个如下文件夹:
$ ls
a b c d
打字except b d
会给a
你c
$ 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' ./*