为什么在这里rm命令不能按照我的期望工作?

3

我只想做一件简单的事情。我在一个目录中有以下文件:

AppInterface.h  baa  PEMsg.h  PluginInterface.h

然后我发出命令:

ls | grep -v ".h" | rm -rf

令我失望的是,baa并没有被删除。但是,这个可以:
ls | grep -v ".h"

我期望得到的是baa,但实际上输出了这个结果。所以我猜测问题出在rm如何接收输入上,但我不知道原因。在csh和bash中都尝试过。

4个回答

8

rm命令无法从stdin接收输入,因此您无法将文件列表管道传输到它。

您需要:

 rm `ls | grep -v ".h"`

或者
ls | grep -v ".h" | xargs rm -rf

rm 从哪里输入?为什么要区分呢? - nakiya
2
Rm 命令只从命令行接受要删除的文件列表。反引号 `` 版本执行 ls 和 grep,并将输出替换为 rm 命令行上的内容。xargs 从 stdin 获取输入,并使用输入作为命令行参数调用命令(在本例中为 rm -rf)。当需要处理大量输入或需要在将其传递给命令之前对输入进行复杂处理时,xargs 更好用。 - The Archetypal Paul
1
如果仅考虑可读性,你应该使用 $( ... ) 而不是反引号。 - sorpigal
2
使用 $() 是标准的 POSIX,已经有一段时间了。反引号有时打起来更快,但在需要嵌套引号的行上会导致很多混乱。请参见此处的文档。这绝对不是 bash 独有的。 - sorpigal
@Paul:我不知道csh是否支持它。出于好奇,我刚在FreeBSD 7上用tcsh测试了一下,结果不起作用,这有点令人惊讶。因此,为了最大的可移植性,即使它们是已弃用的语法,反引号可能仍然是必需的。但是,FreeBSD的sh确实支持这种语法。 - sorpigal
显示剩余3条评论

4

您想要使用xargs

ls | grep -v ".h" | xargs rm -rf

2
“rm” 命令不能从标准输入读取文件列表,这就是为什么它不起作用的原因。您无法将文件名列表管道传输到 “rm” 命令。
正确的方法是:
find . -maxdepth 1 -not -name '*.h' -exec rm -rf {} +

使用多用途的find实用程序。如果你觉得这似乎很费力:那就是正确性的代价。但是,一旦你熟悉了find,它其实并不比这更糟糕。

找到是做这件事的方法,特别是因为您可以轻松检查输出而不会遇到麻烦。 - Blitz
我不确定“正确的方式”完全准确。这只是其中之一,还有其他几种方式。 - Bryan Oakley
1
我很确定。当文件名包含空格字符时,所有其他选项都会失败。这种方法不会失败,因此它必须是“正确的方法”。非常感谢这个救命稻草! - Paul
@Paul:有些人会说find . -maxdepth 1 -not -name '*.h' -delete更正确,这可能是真的。 - sorpigal

1

rm 命令不会从标准输入中获取其参数。您可能正在寻找的是命令替换(在此处用反引号表示),其中一个命令的结果可以插入到另一个命令的参数中:

 rm -rf `ls | grep -v ".h"`

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接