为什么“rm -i”不能在“while”中循环查找“find”的输出?

时间:2018-04-11 13:30:05

标签: bash

如果我执行

find . -name \*\.txt | while read f; do /bin/rm -i "$f"; done

rm问道:

  

/ bin / rm:使用spaces.txt删除常规空文件'./some文件名'?

但命令退出而不等待答案。为什么这样以及如何解决它?

关于此主题的另一个问题,https://unix.stackexchange.com/questions/398872/rm-ir-does-not-work-inside-a-loop循环遍历ls输出,但在我的情况下STDINfind的输出,包含多个文件,每个文件都有可能其中有空格,所以我无法切换到非循环方式。

3 个答案:

答案 0 :(得分:3)

while IFS= read -r -d '' f <&3; do
  rm -i -- "$f"
done 3< <(find . -name '*.txt' -print0)
  • 将内容放在与read -i用于输入的文件描述符不同的文件描述符上。在这里,我们在重定向上使用FD 3(3<,仅在<&3上使用read
  • 清除IFS,或文件名中的前导和尾随空格将被删除。
  • -r传递给read,或文件名中的文字反斜杠将由read使用,而不是放在已填充的变量中。
  • 使用NUL分隔的流或包含换行符的文件名(是的,它们可能发生!)将破坏您的代码。为此,请使用-print0侧的find-d ''侧的read

答案 1 :(得分:2)

使用-print的{​​{1}}操作,而不是循环find find行动所产生的内容:

-exec

在此命令中,find . -name \*\.txt -exec rm -i -- {} + 表示由{}迭代的元素,而find都会分隔+执行的命令,并声明它应该替换find -exec它可以同时使用尽可能多的元素(作为替代方案,您可以使用{}为每个元素执行一次命令)。 \;之后的--确保rm -i列出的文件不会被解释为find选项,如果它们以短划线开头但正确作为文件名。

这不仅更简洁(虽然不容易理解),但它也避免了与天真解决方案所具有的特殊字符相关的问题。

答案 2 :(得分:-1)

因为rm从循环继承了它的标准输入,循环连接到左侧的输出。因此,在read f获得名称foo之后,rm无法从标准输入读取。这就是rm自行退出的原因。

如果您需要rm -i提示,请不要使用管道。有很多选择。其中之一是

rm -i $(echo foo)