使用rm $ {ls)删除文件有什么缺点吗?


13

我想知道rm $(ls)用来删除文件(或rm -r $(ls)删除目录)是否安全?因为在所有网站中,即使此命令比其他命令看起来容易得多,人们也提供了其他方法来执行此操作。


3
基本答案,不。ls无法处理特殊字符。我可以写一个答案来更详细地解释这一点
Sergiy Kolodyazhnyy

5
touch 'foo -r .. bar'; rm $(ls); 我的父目录去哪里了?另外,您看到哪种替代方案比这还要复杂? rm *更容易打字和思考,也更安全(但并非绝对安全;请参阅丹尼斯的答案)。
彼得·科德斯

1
除了出色的答案外,请注意,ls不同的实现可能会有所不同,因此是非标准的。根据需要,考虑诸如find和的替代方案stat。您ls只应将其用于人类消费,而不应被其他命令或脚本使用。
帕迪·兰道

Answers:


7

这打算做什么?

  • ls 列出当前目录中的文件
  • $(ls)替换ls作为参数的场所的输出rm
  • 本质上rm $(ls)是旨在删除当前目录中的所有文件

这幅画怎么了?

ls无法正确处理文件名中的特殊字符。Unix用户通常建议使用不同的方法。在有关文件名计数的一个相关问题中,我还展示了这一点。例如:

$ touch file$'\n'name                                                                                                    
$ ls                                                                                                                     
file?name
$ rm $(ls)
rm: cannot remove 'file': No such file or directory
rm: cannot remove 'name': No such file or directory
$ 

而且,正如Denis的答案中正确提到的那样,带前划线的文件名可以解释为rm替换后的参数,这违背了删除文件名的目的。

什么有效

您要删除当前目录中的文件。所以使用glob rm *

$ ls                                                                                                                     
file?name
$ rm $(ls)
rm: cannot remove 'file': No such file or directory
rm: cannot remove 'name': No such file or directory
$ rm *
$ ls
$ 

您可以使用find命令。经常建议将该工具用于当前目录以外的其他地方-它可以递归遍历整个目录树,并通过-exec . . .{} \;

$ touch "file name"                                
$ find . -maxdepth 1 -mindepth 1                                                                                         
./file name
$ find . -maxdepth 1 -mindepth 1 -exec rm {} \;                                                                          
$ ls
$ 

Python在文件名中没有特殊字符的问题,因此我们也可以使用它(请注意,这仅用于文件,您将需要使用,os.rmdir()并且os.path.isdir()如果要在目录上进行操作):

python -c 'import os; [ os.remove(i) for i in os.listdir(".") if os.path.isfile(i) ]'

实际上,~/.bashrc为简便起见,上述命令可以转换为函数或别名。例如,

rm_stuff()
{
    # Clears all files in the current working directory
    python -c 'import os; [ os.remove(i) for i in os.listdir(".") if os.path.isfile(i) ]'

}

的Perl版本将是

perl -e 'use Cwd;my $d=cwd();opendir(DIR,$d); while ( my $f = readdir(DIR)){ unlink $f;}; closedir(DIR)'

1
"$(ls)"仅当目录中只有一个文件时,您的示例才有效。您最好只使用制表符补全来扩展文件名,因为它是唯一的补全。
彼得·科德斯

确实,@ PeterCordes是一个奇怪的原因,它只能处理一个文件。这是另一个理由反对使用ls呢:)我将修改它
谢尔盖Kolodyazhnyy

我不会说这是一个奇怪的原因:要么引用$(ls)以禁用分词,要么让分词发生(导致灾难性的结果)。传递多个字符串列表而不将数据视为代码的唯一干净方法是使用数组变量或使用\0分隔符,但是shell本身无法做到这一点。仍然IFS=$'\n'是最不危险的,但无法匹配find -print0 | xargs -0。或者grep -l --null。或者,您可以避免诸如此类的整个问题find -exec rm {} +。(请注意+,将多个arg传递给rm的每次调用; WAY效率更高)。
彼得·科德斯

@PeterCordes Yup,完全同意。但是IFS=$'\n'在这种情况下也将失败,因为我在文件名中使用了换行符,所以单词拆分会将其视为两个文件名而不是一个文件名。但是,奇怪的原因是,默认情况下IFS,space,tab,newline,原始文件rm "$(ls)"也应该失败,它应该像我说的文件名那样被视为两个单独的文件名,但事实并非如此。通常我用find-exec,或find . . .-print0 | while IFS= read -d'' FILENAME ; do . . . done结构来处理文件名。或者可以使用python,我已经添加了示例。
Sergiy Kolodyazhnyy 2016年

"$(ls)"总是扩展到一个arg,因为引号可以防止扩展的$(ls)单词分裂。就像他们保护"$foo"
彼得·科德斯

26

不,这并不安全,而且常用的替代方法rm *也不太安全。

很多问题rm $(ls)。正如其他人已经在其答案中涵盖的一样,的输出ls将在内部字段分隔符中出现的字符处进行拆分。

最好的情况是,它根本不起作用。在最坏的情况下,您打算仅删除文件(而不删除目录),或使用选择性删除某些文件,-i但是c -rf当前目录中有一个名称相同的文件。让我们看看发生了什么。

$ mkdir a
$ touch b
$ touch 'c -rf'
$ rm -i $(ls)
$ ls
c -rf

该命令rm -i $(ls)只应删除文件并在删除每个文件之前询问,但最终执行的命令为只读

rm -i a b c -rf

所以它完全做了其他事情。

请注意,这rm *仅稍好一点。使用以前的目录结构,它将按预期的方式运行,但是如果您有一个名为的文件-rf,那么您仍然不走运。

$ mkdir a
$ touch b
$ touch ./-rf
$ rm -i *
$ ls
-rf

有几种更好的选择。最简单的方法仅涉及rm和glob。

  • 命令

    rm -- *
    

    将完全按照预期的方式工作,--表示不应将其后的所有内容解释为一种选择。

    二十多年来,这一直是POSIX实用程序语法准则的一部分。它很普遍,但是您不应该期望它随处可见。

  • 命令

    rm ./*
    

    使全局扩展不同,因此不需要调用实用程序的支持。

    对于上面的示例,您可以看到将通过在echo前面添加最终执行的命令。

    $ echo rm ./*
    rm ./a ./b ./-rf
    

    前导./防止rm意外地将任何文件名都视为选项。


1
很好的一点是,带有-扩展名的文件名成为的标志rm。+1
Sergiy Kolodyazhnyy

1
甚至更讨厌:touch 'foo -rf .. bar。我认为,除非我们可以在ls的输出中生成路径分隔符,否则攻击者无法获得比父目录更高的目录。
彼得·科德斯

@Peter攻击者首先必须具有写入权限才能删除专利目录,不是吗?
Sergiy Kolodyazhnyy

1
@PeterCordes我不确定rm的所有版本是否都具有此故障保护功能,但是在Ubuntu,openSUSE和Fedora上,rm: refusing to remove '.' or '..' directory: skipping '..'尝试删除父目录时会说或类似的内容。
丹尼斯

@Serg:攻击者只是向您发送一个带有该文件名的.zip文件,您可以通过提取该文件然后尝试删除其内容来使自己陷入困境。或者通过在/ var / tmp之类的文件中创建该文件名。
彼得·科德斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.