英文:
The command "rm -rf !(a)" doesn't work in bash -c syntax
问题
在家庭目录中有三个文件,分别命名为 'a'、'b' 和 'c'。我使用了 "rm -rf !(a)" 命令来删除 'b' 和 'c' 文件,在 bash 命令行中运行时,它正常工作。如下所示:
xx@xx:~/# ls
a b c
xx@xx:~/# rm -rf !(a)
xx@xx:~/# ls
a
然而,当我使用 "bash -c" 来运行它时,它给我报了一个语法错误,如下所示:
xx@xx:~/# ls
a b c
xx@xx:~/# bash -c "rm -rf !(a)"
bash: -c: line 0: syntax error near unexpected token '('
bash: -c: line 0: 'rm -rf !(a)'
然后我在 '!'、'(' 和 ')' 前面添加了反斜杠符号 ''。尽管没有错误发生,但我发现它不起作用。如下所示:
xx@xx:~/# ls
a b c
xx@xx:~/# bash -c "rm -rf \!(a)"
xx@xx:~/# ls
a b c
有人能帮忙澄清这个问题吗?
英文:
There are three files in family dir named 'a' 'b' 'c'. I used "rm -rf !(a)" to delete the 'b' and 'c' files, after run it in bash CLI, it worked fine. As below:
xx@xx:~/# ls
a b c
xx@xx:~/# rm -rf !(a)
xx@xx:~/# ls
a
However, when I was running it by "bash -c", it threw a syntax error to me, that is as below:[![enter image description here]
xx@xx:~/# ls
a b c
xx@xx:~/# bash -c "rm -rf !(a)"
bash: -c: line 0: syntax error near unexpected token`('
bash: -c: line 0:`rm -rf !(a)'
Then I added backslash before '!', '(' and ')'. Although, there is not error occur; I found it did not work. As below:
xx@xx:~/# ls
a b c
xx@xx:~/# bash -c "rm -rf \!\(a\)"
xx@xx:~/# ls
a b c
Could any body can help to clarify this problem?
答案1
得分: 5
不要滥用 extglob
模式。
不要滥用“not”逻辑。
不要滥用 globs。
请千万不要在 root
用户下除了几乎是极度谨慎的情况下,使用 rm -fr
删除任何东西。
如果在该目录或其任何子目录中有除了 a
以外的任何内容,都将被删除。
如有需要,可以提出进一步问题。
英文:
Don't use extglob
patterns carelessly.
Don't use "not" logic carelessly.
Don't use globs carelessly.
And for all gods' sake, please don't use rm -fr
as root
with anything other than damned-near paranoia.
If you had anything besides a
in that directory, or in any subdirectory of it, it's gone.
$: find
.
./a
./abc
./bar
./bcd
./efg
./efg/hij
./efg/hij/klm
./foo
./x
./y
./y/deleteme
./y/deleteme/stuff
$: bash -O extglob -c 'echo rm -fr !(x)'
rm -fr a abc bar bcd efg foo y
Obviously, it grabs everything that is, as you asked, not x
.
As Ted Lyngmo pointed out in his comment above,
> rm -rf [^a]
would do if you want to remove all one letter files and directories except a
. If you want to remove b
and c
explicitly: rm -rf [bc]
... or rm -rf b c
...
Simple, clear, and specific is virtually always better when it's an option.
Added by Ted:
> If you want to remove all files except b
and c
in the current directory (which is what you asked for in a comment) you could again use find
with the extension -maxdepth 1
to only make it search in the current directory:
find . -maxdepth 1 -type f \! \( -name b -o -name c \) -exec echo {} +
> Replace echo
with rm -f
if you are sure you want to delete those listed. The find
version included in [tag:linux] has some more extensions making it possible to skip providing the top directory .
and it also has a -delete
option to delete files:
# danger zone below:
find -maxdepth 1 -type f \! \( -name b -o -name c \) -delete
(Thanks, Ted - I was just coming back to add this, lol)
> Paul Hodegs, you are right, however there is a case that i need keep some specified file or sub-dir in a certain dir, we need to remove the other dirty data in this dir regularly to avoid limited disk no-free case caused by some partners forgetting remove his/her research data in this dir after he or she used. –
Yayong Duan
Valid, in which case your original question is (sort of) a programming question. Be very careful to always assert that you are working in/on the right directory, and careful that maybe you back up your data pretty often against possible errors, but the important thing in that case is that you explicitly list ALL the files you want to keep in the single command to remove everything else.
In my above example, if you wanted to keep abc
and bcd
, you'd need rm -fr $thatDir/!(abd|bcd)
.
Just be super careful with that, and I strongly suggest using a nonprivileged user.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论