将命令输出传递给rm -r命令

时间:2015-05-20 12:23:33

标签: linux shell

当目录数超过10时,我想删除目录中的旧目录。 当我运行命令时,

sudo rm -r `ls -1t /ebs/lucene_indexes/ | tail -n +10`

我收到以下错误:

rm: cannot remove â1432120954â: No such file or directory
rm: cannot remove â1432120945â: No such file or directory
rm: cannot remove â1432120937â: No such file or directory
rm: cannot remove â1432120927â: No such file or directory
rm: cannot remove â1432120917â: No such file or directory
rm: cannot remove â1432118817â: No such file or directory
rm: cannot remove â1432118631â: No such file or directory
rm: cannot remove â1432118349â: No such file or directory

但是当我执行时:

ls -1t /ebs/lucene_indexes/ | tail -n +10

我得到以下输出:

1432120954
1432120945
1432120937
1432120927
1432120917
1432118817
1432118631
1432118349

出于某种原因,当我执行第一个命令时,目录名称会被追加并由特殊字符添加前缀。所以它失败了。为什么会这样?这里出了什么问题?

3 个答案:

答案 0 :(得分:4)

我怀疑您执行/ebs/lucene_indexes/时不在ls目录中,这意味着列出的目录不在您当前的工作目录下。我会cd进入目录并从“。”执行ls。我不记得有任何简单的方法让find按时间排序,

也是如此
(cd /ebs/lucene_indexes/; sudo rm -r $(ls -t | tail -n +10 ))

得到你想要的东西?请注意,周围的括号在子shell中执行cd,因此现有的cwd不会更改。此外,管道中不需要-1

答案 1 :(得分:2)

xargs是你的朋友,例如:

ls -1t /ebs/lucene_indexes/ | tail -n +10 | xargs rm -r

干杯,

答案 2 :(得分:1)

mpez0's answer包含关键指针rm命令不一定在/ebs/lucene_indexes/中运行,因此,当从其他目录运行时,它会使用ls -1t生成的仅文件名输出失败。

mpez0的答案解决了这个问题,但是,就像OP的命令一样,它打破了带有嵌入空格的文件名;这是正确处理带有嵌入空格的文件名的版本

(cd /ebs/lucene_indexes/ && \ls -t | tail -10 | sudo xargs -I {} rm -r -- {})

它使用xargs来读取ls的输出行,并为每个输出行rm调用-I,每行作为单行命令行参数;这个符合POSIX标准的xargs用法的缺点是你得到多个 rm个调用。

使用GNU xargs能够使用-0选项解析NUL分隔的输入,通过xargs传递,您可以提高命令效率尽可能多的参数适合命令行,导致(通常)仅一次调用rm

(cd /ebs/lucene_indexes/ && \ls -t | tail -10 | tr '\n' '\0' | sudo xargs -0 rm -r --)
  • tr '\n' '\0'用NUL(0x0)替换换行符,准备按xargs -0进行处理。
  • xargs -0 rm -r --将所有NUL分隔的标记从stdin传递为命令行参数rm -r,从而导致(通常)仅一个调用rm
    • 请注意,使用NUL分隔的输入可以正确地保留带有嵌入空格(甚至制表符)的路径作为不同的参数。如果没有tr '\n' '\0' / xargs -0组合,只有xargs rm -r,带有嵌入空格的路径会被错误地分解为多个参数,从而导致rm失败

注意ls的配置方式(--color行为,绕过名为ls的潜在别名\ls),如评论中所述,也值得,但这让我们得到了更大的一点:它是generally not a good idea to parse ls output,因为通常有更好更强大的替代方案(globbing,find)。

不幸的是,在这种情况下避免ls 会严重地使命令复杂化。继续阅读基于find的解决方案。

注意:在一天结束时,这个基于find的解决方案与基于ls的解决方案相比没有太大的优势,因为它也不适用于带有嵌入换行符的文件名;然而,会帮助处理包含标签字符(\t等异域字符的文件名,ls通常在输出中表示为?

find /ebs/lucene_indexes -mindepth 1 -maxdepth 1 -printf '%T@\t%p\n' | 
 sort -n | head -10 | cut -f2- | tr '\n' '\0' | sudo xargs -0 rm -r --

注意:在以下说明中,“file”指的是文件和目录。

  • find /ebs/lucene_indexes -mindepth 1 -maxdepth 1相当于ls /ebs/lucene_indexes,但它返回路径,而不仅仅是文件名(并且输出不会被排序)。
  • -printf '%T@\t%p\n'在纪元时间(%T@)输出每个文件的最后修改日期,然后是标签,后跟文件的完整路径(%p)。
  • sort -n然后对输出进行排序,以便首先列出最旧的文件,然后head -10输出最旧的10个文件。
  • cut -f2-从输出中删除日期列,只留下完整路径。
  • tr '\n' '\0'xargs -0 rm -r --按上述方式工作。