ls *,ls **和ls ***的结果


86

我知道使用命令ls将列出所有目录。但是该ls *命令有什么作用?我用它,它只是列出目录。前面的星星是否ls意味着可以列出目录的深度?

Answers:


155

ls列出要作为参数传递的目录的文件和目录内容,如果没有给出参数,则列出当前目录。还可以通过许多影响其行为的选项(man ls有关详细信息,请参见)。

如果ls传递了一个名为的参数*,它将*在当前目录中查找一个名为的文件或目录,并像其他任何目录一样列出它。ls不会*以任何其他方式对待角色。

但是,如果ls *是一个外壳命令行,则该外壳将其扩大*根据相应的外壳的通配符(也被称作文件名生成文件名扩展)的规则。

尽管不同的外壳支持不同的globing运算符,但大多数都同意最简单的一个**模式代表任意数量的字符,因此*a glob将扩展到与该模式匹配的当前目录中的文件列表。但是,有一个例外,即.文件名中的前导点()字符必须显式匹配,因此*实际上扩展为不是以.(按字典顺序)开头的文件和目录列表。

举例来说,如果当前目录包含一个称为文件....foo-lfoo bar*将由外壳扩展到两个参数传递给ls-lfoo bar,所以这将是,如果你输入了:

ls -l "foo bar"

要么

'ls' "-l" foo\ bar

这是运行完全相同的命令的三种方式。在这3种情况下,该ls命令(可能会从中/bin/ls提到的目录中执行$PATH)都将传递这3个参数:“ ls”,“-l”和“ foo bar”。

顺便说一句,在这种情况下,ls将第一个(严格来说讲第二个)作为选项。

现在,正如我所说,不同的外壳具有不同的全局操作符。几十年前,zsh引入了**/运算符¹,它表示要匹配任何级别的子目录,简称,(*/)#并且***/与之相同,只是它在降序时遵循符号链接。

几年前(2003年7月ksh93o+),ksh93决定复制该行为,但决定使其为可选项,并且仅涵盖了这种**情况(未涉及***)。另外,尽管**单独使用并没有什么特别之处zsh(与*其他传统shell一样,它的含义相同,因为它**意味着任意数量的字符后接任意数量的字符),但在ksh93中,**含义相同**/*(因此当前目录下的任何文件或目录都一样) (不包括隐藏文件)。

bashksh93在几年后(2009年2月,bash 4.0)复制,具有相同的语法,但不幸的**是:bash 类似于zsh***,即递归到子目录时遵循符号链接,这通常不是您想要的,会产生讨厌的副作用。它在bash-4.3中已部分修复,因为仍然遵循符号链接,但递归在那里停止了。它已在5.0中完全修复。

yash**在2008年的2.0版中添加,并启用了该extended-glob选项。它的实现更接近zsh,因为**它并不特殊。在2.15版(2009)中,它添加了***in zsh和两个自己的扩展名:.**.***在递归时包括隐藏的目录(在中zshD glob限定符(如**/*(D))将考虑隐藏的文件和目录,但是如果您只想遍历隐藏的目录目录,但不展开隐藏文件,您需要((*|.*)/)#***/[^.]*(D))。

鱼外壳也支持**。与的早期版本一样bash,在降级目录树时,它也会遵循符号链接。但是在该外壳中**/*与并不相同****更大的扩展*是可以跨越多个目录。在fish**/*.c将匹配a/b/c.c而不是a.c,同时a**.c将匹配a.cab/c/d.czsh**/.*,例如已被写入.* **/.*。在那里,***被理解为**与之*相同**

tcshglobstar在V6.17.01(2010年5月)中还添加了一个选项,并支持*****àla zsh

所以tcshbashksh93,(当相应的选项启用(globstar)),或者fish**扩展所有低于当前的文件和目录,并且***是一样**fish,一个符号链接遍历**tcshglobstar,和同为*bashksh93(尽管它这些shell的未来版本也将遍历符号链接并非没有可能)。

在上面,您已经注意到有必要确保没有将任何扩展解释为选项。为此,您可以这样做:

ls -- *

要么:

ls ./*

在某些命令中(对于没关系ls),第二个命令更可取,因为即使使用了--一些文件名,它们也可能会被特殊对待。-对于大多数文本实用程序而言,情况就是这样,cd并且pushd包含例如=字符的文件名也是如此awk./在所有参数之前加上它们将删除其特殊含义(至少对于上述情况而言)。

还应当指出的是,大部分炮弹有一些影响的通配符行为的选项(如点文件是否被忽略与否,排序顺序,做什么,如果没有匹配...),也见$FIGNORE参数ksh

此外,在每一个外壳,但cshtcshfishzsh,如果文件名匹配模式不匹配任何文件,该模式被作为引起混乱,并可能错误未扩展参数传递。例如,如果当前目录中没有非隐藏文件

ls *

实际上会调用ls两个参数ls*。而且由于根本没有文件,因此也没有任何文件*,您会看到ls(不是shell)发出的错误消息,例如:ls: cannot access *: No such file or directory,它使人们认为这ls实际上是在扩展全局范围。

在以下情况下,问题甚至更严重:

rm -- *.[ab]

如果没有*.a,也没有*.b文件在当前目录下,那么你可能最终删除一个名为*.[ab]错误(cshtcsh,和zsh将报告不匹配错误,并不会要求rm(和fish不支持[...]通配符))。

如果确实要将文字传递*ls,则必须以或或的*某种方式引用该字符。在类似POSIX的shell中,可以使用或一起禁用globing (除非在/ 仿真中,否则后者不起作用)。ls \*ls '*'ls "*"set -o noglobset -fzshshksh


¹尽管(*/)#一直受到支持,但它首先像..../zsh-2.0(甚至可能在以前)中是简写****/形式,然后是2.1 ,然后在2.2中获得确定的形式**/(1992年初)


22
真是个好答案!
Andrea Corbellini 2013年

7
另一个很好的例子是find -name *。特别是使用更复杂的模式时,如果当前目录中只有一个匹配项,人们通常不会意识到他们没有将星号传递给find
njsg 2013年

我继续给+1,我真的很高兴看到斯蒂芬Chazelas活跃在这里unix.stackexchange.com!史蒂芬(Stephane)一如既往!
Dimitre Radoulov

1
在fish中,*.[ab]将尝试删除以结尾的所有内容.[ab][鱼不是特别的。
Konrad Borowski14年

35

该命令ls默认为ls .列出当前目录中的所有条目

该命令的ls *意思是“在*shell模式的扩展上运行ls ”

*模式由外壳程序处理,并扩展到当前目录中的所有条目,但以.。开头的条目除外。它将深入一层。

双重或三重*模式的解释取决于实际使用的外壳。

*是匹配0个或多个字符的通配符。一些现代的shell将在看到**模式后递归到子目录中。


17
除了额外的* 功能外,请参阅其他答案来解释globstar。还应该明确的是,ls 与星号无关,它根本没有经过任何这些星号。运行echo ls *以查看编写时将执行的操作ls *
njsg

12

您可以通过键入echo而不是ls第一个来使整个过程神秘化,以查看命令扩展到的内容:

$ echo *
Applications Downloads Documents tmp.html

因此,在这种情况下,ls *扩展为ls Applications Downloads Documents tmp.html

$ echo **
Applications Downloads Documents tmp.html

$ echo ***
Applications Downloads Documents tmp.html

所以没有变化。假设您使用的bash是您的外壳程序-大多数人都是这样,并且不同的外壳程序具有不同的行为。如果您使用ashcshkshzsh,则可能会期望事情有所不同。这就是拥有不同外壳的要点。

因此,让我们尝试一些不同的事情(仍然使用bash),以便我们了解一下globlob(*)运算符可以为我们做些什么。例如,我们可以按名称的一部分进行过滤:

$ echo D*
Downloads Documents

有趣的是,斜杠是任何目录名称的隐含部分。因此*/将仅产生目录(以及目录的符号链接):

$ echo */
Applications/ Downloads/ Documents/

我们可以通过在中间添加斜线来在多个级别进行一些过滤:

$ echo D*/*/
Documents/Work/ /Documents/unfinished/

由于该Downloads目录不包含任何子目录,因此它不会最终出现在输出中。这对于仅检查所需文件非常有用。我一直在使用这样的命令:

$ ls -l /home/*/public_html/wp-config.php

如果有的话,它将列出wp-config.php任何用户public_html目录的基本级别上存在的所有文件。或者可能更完整:

$ find /home/*/public_html/ -name wp-config.php

这样可以wp-config.php在任何用户的public_html目录或其子目录中找到任何文件,但它的运行效率将远远高于仅find /home/ -name wp-config.php检查每个用户的目录,不是检查任何public_html目录。


1
“这假定您使用的bash是外壳程序”←,并且未启用globstar。shopt -s globstar然后再试一次...
njsg 2013年

另一种揭开神秘面纱的方法是set -x,它将开始打印每次执行的“实际”命令(使用关闭set +x)。
ShreevatsaR


1

如果要“深入研究”,请使用ls -R(递归)选项,或使用find,如下所示:

find . -ls

“ find”会跳到目录树的底部('ls -R'也是如此),并且具有更多选项,例如列出目录(-d型),仅文件(-f型)或显示具有其他目录的文件。特征(/ etc / passwd中没有用户,特定权限以及更多)。在脚本编写中,“查找”也更安全(由于外壳之间的不一致的定位规则,以及带有破折号的文件的特殊转义符等)。

在点文件上,仅使用星号'*'不能使Shell通配符遍历。要仅列出点文件,请使用:

ls .??*


-1

额外*不会增加深度级别。但是如果你尝试

 ls */*/*

-您将获得当前文件夹中文件夹的子文件夹的子文件夹列表...


错误。根据外壳,extra *会增加深度级别。
njsg

那么什么壳会增加额外恒星的深度等级?
VB9-UANIC

一些。包括bash带有globstar选项的GNU ,korn shell和zsh。我猜可能还有其他人。unix.stackexchange.com/a/62665/14831
njsg

-1

我的主要把握是echo ** / *。ext通常会...

可能会或可能不会:在当前目录中列出一个.ext文件

可能会或可能不会:包括。*。ext文件

通常,我希望将glob表达式设置为'** /',并且这可能导致字符串为空(无子目录)。这就是我在程序输入中转换glob表达式的方式。当然,我确实确保在使用示例中有注释来解释这一点。

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.