【问题标题】:Linux why can't I pipe find result to rm?Linux 为什么我不能通过管道找到结果到 rm?
【发布时间】:2013-12-16 22:07:13
【问题描述】:

对不起,如果这是一个菜鸟问题,但我找不到好的答案。

找到然后删除我可以使用的东西

find . -name ".txt" -exec rm "{}" \;

但是为什么我不能像管道一样将结果传递给 rm

find . -name ".txt" | rm 

就像我将它通过管道传递给 grep

find . -name ".txt" | grep a

我从某处读到 rm 不接受来自标准输入的输入,因此我无法通过管道传输它,但这是什么意思?当我输入 rm a.txt 时,它会从标准输入中读取,就像我可以 grep 一样,对吗?还是标准输入和命令行之间有区别。救命!

【问题讨论】:

    标签: linux bash find pipe rm


    【解决方案1】:

    找到 . -名称“.txt”| grep "foo" | xargs -I{} rm {}

    【讨论】:

      【解决方案2】:

      不使用管道的替代方法:

      xargs rm -f <<< $(find . -name ".txt")
      

      【讨论】:

        【解决方案3】:

        扩展@Alex Gitelman 的回答:是的,“标准输入”和命令行之间是有区别的。

        当您键入rm a.txt b.txt c.txt 时,您在rm 之后列出的文件称为参数,并且可通过特殊变量(内部称为argv)提供给rm。另一方面,标准输入看起来像一个名为stdin 的文件的Unix 程序。程序可以从这个“文件”中读取数据,就像它在磁盘上打开一个常规文件并从中读取一样。

        rm 与许多其他程序一样,从命令行获取参数,但忽略标准输入。你可以通过管道传输任何你喜欢的东西;它只会丢弃这些数据。这就是xargs 派上用场的地方。它读取标准输入上的行并将它们转换为命令行参数,因此您可以有效地将数据通过管道传输到另一个程序的命令行。这是一个巧妙的技巧。

        例如:

        find . -name ".txt" | xargs rm
        find . -name ".txt" | grep "foo" | xargs rm  
        

        请注意,如果有任何文件名包含换行符或空格,这将无法正常工作。 要处理包含换行符或空格的文件名,您应该改用:

        find . -name ".txt" -print0 | xargs -0 rm
        

        这将告诉find 以空字符而不是换行符终止结果。 但是,grep 不会像以前那样工作。而是使用这个:

        find . -name ".txt" | grep "foo" | tr "\n" "\0" | xargs -0 rm
        

        这次tr 用于将所有换行符转换为空字符。

        【讨论】:

        • 谢谢,这是一个很好的答案。但是我如何判断一个命令是带参数还是标准输入,因为在语法上它们都写为command something。它包含在手册页中吗?
        • 这不是它的工作原理。按照惯例,许多从文件读取的命令也将从标准输入读取,但前提是 no 文件在命令行参数中命名。示例:cat、less、grep、sort、sed。但是是的,一般来说,如果没有给出参数,手册页应该说明命令是否从标准输入读取。 (留给 Unix 手册页作者的文档。经典 Unix 工具的文档往往比新工具更一致。警告购买者。)
        • @user1297061 是的,它包含在手册页中。如果手册页没有说命令接受来自标准输入的输入,那么它不会
        • 还有一些命令只有在给出文件名 - 时才允许使用标准输入。例如 vim:ls | vim - 在 vi​​m 中有 ls 的输出。
        • 这对我很有用。我没有使用-name ".txt",而是使用了-print,其余部分仍然有效。谢谢!
        【解决方案4】:

        “为什么我不能通过管道将 find 结果发送到 rm?”

        当您将某些内容通过管道传输到程序时,管道会替换键盘输入。记住这一点,然后问自己下一个问题:rm 会用键盘做什么?删除你的击键? (确实有点傻)接受交互式控制? (rm 不是交互式的,除非有时需要确认,这确实可以通过管道给出。)

        事实上,当rm 已经运行时,你不能输入命令让它删除文件......所以你也不能用管道来做。

        如果您牢记管道取代了键盘/屏幕组合,事情会立即显得更合乎逻辑。

        现在反过来了。 您可以将数据流通过管道传输到grep。 这是否意味着您可以让 grep 将键盘上的击键作为输入数据读取?

        是的!这实际上是它本机(没有管道)所做的。

        (顺便说一句,请注意,您不能通过管道将搜索参数输入grep

        所以现在你知道为什么你不能通过管道连接到 rm 并且期望它作为命令行参数工作。

        tl;博士:

        根据 UNIX 哲学剖析程序:
        文件输入、文件输出、键盘输入、屏幕输出。 -> Pipe 只替换键盘和屏幕。

        【讨论】:

        • 我很确定rm &lt;(...) 会尝试删除/proc/fd/123 之类的内容。
        • 是的,我看到了我的错误。这周我睡得很少。我已经更新了它。谢谢你的评论。我很感激。
        【解决方案5】:

        Pipe 将第一个命令的输出发送到第二个命令的标准输入。 rm 不接受标准输入,因此您无法通过管道输入。你可以使用xargs 来达到同样的效果。 您可以在 man page for xargs 中找到专门针对您的案例的 xargs 示例。

        【讨论】:

          猜你喜欢
          • 2012-06-26
          • 2012-10-05
          • 2021-05-11
          • 1970-01-01
          • 2022-10-23
          • 1970-01-01
          • 1970-01-01
          • 2011-03-21
          • 2014-09-21
          相关资源
          最近更新 更多