ls总是列出rm将删除的文件吗?
我觉得我应该知道的事情是:如果我ls
, rm
删除与ls
显示完全相同的文件吗? 是否有任何情况下rm
可以删除ls
未显示的文件? (这是在18.04 bash)
编辑:谢谢所有回答的人。 我认为完整的答案是所有答案的组合,所以我已经接受了最多投票的答案作为“答案”。
我一路上学到了意想不到的事情:
- 在处理其论点时,
ls
并不像你想象的那么简单 - 在一个简单的un-fiddled-with Ubuntu中,.bashrc别名
ls
- 不要用破折号命名你的文件,因为它们看起来像命令参数,命名一个-r就是要求它!
好吧, ls
和rm
对传递给它们的参数进行操作。
这些参数可以是一个简单的文件,因此ls file.ext
和rm file.ext
在同一个文件上运行,结果清晰(列出文件/删除文件)。
如果相反参数是一个目录, ls directory
列出目录的内容 ,而rm directory
将不能正常工作(即没有标志的rm
不能删除目录,而如果你做rm -r directory
,它递归删除目录下的所有文件 和目录本身 。
但请记住,命令行参数可以进行shell扩展 ,因此如果它们包含通配符,变量,其他命令的输出等,并不总是保证将相同的参数传递给两个命令。
作为一个极端的例子,想想ls $(rand).txt
和rm $(rand).txt
,参数是“相同的”,但结果却截然不同!
如果您正在考虑类似ls foo*.txt
与rm 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行为,让我们只关注rm
和ls
可以处理自己的问题。 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:
基本上通配符扩展到以-
(或手动输入的东西开头-
但看起来更像是作弊)的东西可能会被ls
和rm
不同地解释。
有一些边缘情况, 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
,你会发现自己经常使用\rm
或rm -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/baz
。 rm -rf /
是特殊的,但rm -rf /usr
不是! 省略-rf
部分,或以ls
开头,只在输入路径后添加rm -rf
部分。