ls总是列出rm将删除的文件吗?

我觉得我应该知道的事情是:如果我ls rm 删除与ls显示完全相同的文件吗? 是否有任何情况下rm可以删除ls未显示的文件? (这是在18.04 bash)

编辑:谢谢所有回答的人。 我认为完整的答案是所有答案的组合,所以我已经接受了最多投票的答案作为“答案”。

我一路上学到了意想不到的事情:

  • 在处理其论点时, ls并不像你想象的那么简单
  • 在一个简单的un-fiddled-with Ubuntu中,.bashrc别名ls
  • 不要用破折号命名你的文件,因为它们看起来像命令参数,命名一个-r就是要求它!

好吧, lsrm对传递给它们的参数进行操作。

这些参数可以是一个简单的文件,因此ls file.extrm file.ext在同一个文件上运行,结果清晰(列出文件/删除文件)。

如果相反参数是一个目录, ls directory列出目录的内容 ,而rm directory将不能正常工作(即没有标志的rm不能删除目录,而如果你做rm -r directory ,它递归删除目录下的所有文件 和目录本身

但请记住,命令行参数可以进行shell扩展 ,因此如果它们包含通配符,变量,其他命令的输出等,并不总是保证将相同的参数传递给两个命令。

作为一个极端的例子,想想ls $(rand).txtrm $(rand).txt ,参数是“相同的”,但结果却截然不同!

如果您正在考虑类似ls foo*.txtrm foo*.txt ,那么是的,它们将显示并删除相同的文件。 shell扩展了glob,并将其传递给有问题的命令,命令对列出的文件起作用。 一个列出它们,一个删除它们。

明显不同的是,如果这些文件中的任何一个碰巧是一个目录,那么ls会列出其内容,但是rm将无法删除它。 这通常不是问题,因为rm会比ls显示的更少

这里的一个大问题来自于在包含以破折号开头文件名的目录中运行ls *rm * 。 它们将扩展到两个程序的命令行,就像你自己编写它们一样,并且ls-r表示“反向排序顺序”,而rm-r表示递归删除。 如果您的子目录至少有两个级别,则差异很重要。 ( ls *将显示第一级目录的内容,但rm -r *也会超过第一级别的所有内容。)

为了避免这种情况,使用前导./来写入允许的globs以指示当前目录,和/或在glob之前发出--来表示选项处理的结束(即rm ./*rm -- * )。

使用类似*.txt的glob,这实际上不是问题,因为点是一个无效的选项字符,并且会导致错误(直到某人扩展实用程序以发明它的含义),但是放置./仍然更安全。无论如何。


当然,如果你改变了shell的globbing选项,或者在命令之间创建/移动/删除了文件,你也可以得到两个命令的不同结果,但我怀疑你是否意味着任何这些情况。 (安全地处理新的/移动的文件会非常麻烦。)

抛开shell行为,让我们只关注rmls可以处理自己的问题。 ls将显示rm无法删除的至少一种情况涉及目录权限,而其他 – 特殊目录...

文件夹权限

rm是对目录的操作,因为通过删除文件,您正在更改目录内容(或者换句话说,列出目录条目,因为d irectory只不过是文件名和inode的列表 )。 这意味着您需要对目录具有写权限。 即使您是文件的所有者 ,如果没有目录权限,也无法删除文件。 反之亦然 :如果您是目录所有者, rm可以删除其他人拥有的文件。

所以你很可能对目录有读取和执行权限,这将允许你遍历目录并查看内容很好,例如ls /bin/echo ,但你不能rm /bin/echo除非你是/bin所有者或使用sudo提升您的权限。

而且你会在任何地方看到这样的案例。 这是一个这样的案例: https : //superuser.com/a/331124/418028


特殊目录’。’ 和’..’

另一个特例是...目录。 如果你做ls . 或者ls .. ,它会愉快地向你展示内容,但不允许使用它们:

 $ rm -rf . rm: refusing to remove '.' or '..' directory: skipping '.' 

如果你输入ls *然后输入rm * ,你可能会删除比ls显示的文件更多的文件 – 它们可能是在ls结束和rm开始之间的微小时间间隔内创建的。

ls *rm *不负责扩展glob – 在将shell传递给命令之前由shell完成。

这意味着你可以使用扩展文件列表的任何命令 – 所以我会使用尽可能少的东西。

因此,更好的方法(或至少,另一种方式)是跳过中间人。

echo *将准确显示传递给rm命令的内容。

怎么样:

 $ mkdir what $ cd what $ mkdir -p huh/uhm ./-r $ ls * uhm $ rm * $ ls -r $ ls -R .: -r ./-r: 

基本上通配符扩展到以- (或手动输入的东西开头-但看起来更像是作弊)的东西可能会被lsrm不同地解释。

一些边缘情况, ls显示的不是rm删除的内容。 一个相当极端,但幸运的是,如果您传递的参数是目录的符号链接: ls将显示符号链接目录中的所有文件,而rm将删除符号链接,保持原始目录及其内容不变:

 % ln -s $HOME some_link % ls some_link # Will display directory contents bin lib Desktop ... % rm some_link % ls $HOME bin lib Desktop ... 

如果你只做ls而不是ls -a ,是的, rm可以删除你没有看到过没有-a ls隐藏文件。

示例:

根据 :

 dir_test ├── .test └── test2 

ls dir_test :只显示test2

ls -A dir_test :将显示test2 + .test

rm -r dir_test :将删除所有(.test + test2)

我希望这会对你有所帮助。

已经有很多好的答案,但我想补充一些更深刻的见解。

问自己一个问题:如果你写的话,传递给ls参数有多少

 ls * 

…? 请注意,如果有任何*可以展开的文件,则ls命令不会获取* as参数。 相反,shell在调用命令之前首先执行globbing,因此ls命令实际上获得的参数与globbing匹配的文件一样多。 要抑制globbing,请引用参数。

对于任何命令都是如此: echo * vs echo '*'

有一个脚本,称之为countparams.sh来测试效果。 它告诉你它传递了多少参数并列出它们。

 #!/bin/bash echo "This script was given $# parameters." arr=( "$@" ) for ((i=0;i<$#;i++)); do echo "Parameter $((i+1)): ${arr[$i]}" done 

使其可执行并运行./countparams.sh * 。 从它的输出中学习!

如果目录内容在这两个不同的时间相同, 那么 glob将以相同的方式扩展。


如果您确实想要检查要删除的内容,请使用rm -i *.txt 。 它会在(尝试)删除之前单独提示您输入每个文件。

这保证在竞争条件下是安全的:
ls *.txt /创建一个新文件/ rm *.txt
因为正在执行删除的同一程序提示您输入每个文件。


这对于正常使用来说太麻烦了,如果你将rm -i别名为rm -i ,你会发现自己经常使用\rmrm -f 。 但值得一提的是,竞争条件有一个解决方案。 (它甚至可以移植到非GNU系统: POSIX rm(1)指定-i选项 。)

另一种选择是bash数组: to_remove=(*.txt) ,然后要求用户确认(也许在执行ls -ld -- "${to_remove[@]}" ),然后rm -- "${to_remove[@]}" 。 所以全局扩展只进行一次,列表逐字传递给rm

另一个实用的选项是GNU rm -I ( 手册页 ),它会提示是否删除了4个以上的项目。 (但不会显示列表,只显示总数。)我在桌面上使用alias rm='rm -I'

这是一个很好的防止脂肪指法返回的保护措施,半模式匹配太多。 但是首先使用ls通常在您拥有的目录或单用户系统上很好,并且当没有后台进程可以在那里异步创建新文件时。 为了防止指法,请不要从左到右键入rm -rf /foo/bar/bazrm -rf /是特殊的,但rm -rf /usr不是! 省略-rf部分,或以ls开头,只在输入路径后添加rm -rf部分。