Answers:
ls列出要作为参数传递的目录的文件和目录内容,如果没有给出参数,则列出当前目录。还可以通过许多影响其行为的选项(man ls有关详细信息,请参见)。
如果ls传递了一个名为的参数*,它将*在当前目录中查找一个名为的文件或目录,并像其他任何目录一样列出它。ls不会*以任何其他方式对待角色。
但是,如果ls *是一个外壳命令行,则该外壳将其扩大*根据相应的外壳的通配符(也被称作文件名生成或文件名扩展)的规则。
尽管不同的外壳支持不同的globing运算符,但大多数都同意最简单的一个*。*模式代表任意数量的字符,因此*a glob将扩展到与该模式匹配的当前目录中的文件列表。但是,有一个例外,即.文件名中的前导点()字符必须显式匹配,因此*实际上扩展为不是以.(按字典顺序)开头的文件和目录列表。
举例来说,如果当前目录包含一个称为文件.,..,.foo,-l和foo bar,*将由外壳扩展到两个参数传递给ls:-l和foo 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和两个自己的扩展名:.**并.***在递归时包括隐藏的目录(在中zsh,D glob限定符(如**/*(D))将考虑隐藏的文件和目录,但是如果您只想遍历隐藏的目录目录,但不展开隐藏文件,您需要((*|.*)/)#*或**/[^.]*(D))。
该鱼外壳也支持**。与的早期版本一样bash,在降级目录树时,它也会遵循符号链接。但是在该外壳中**/*与并不相同**。**更大的扩展*是可以跨越多个目录。在fish,**/*.c将匹配a/b/c.c而不是a.c,同时a**.c将匹配a.c和ab/c/d.c和zsh的**/.*,例如已被写入.* **/.*。在那里,***被理解为**与之*相同**。
tcshglobstar在V6.17.01(2010年5月)中还添加了一个选项,并支持**和***àla zsh。
所以tcsh,bash和ksh93,(当相应的选项启用(globstar)),或者fish,**扩展所有低于当前的文件和目录,并且***是一样**的fish,一个符号链接遍历**了tcsh与globstar,和同为*中bash和ksh93(尽管它这些shell的未来版本也将遍历符号链接并非没有可能)。
在上面,您已经注意到有必要确保没有将任何扩展解释为选项。为此,您可以这样做:
ls -- *
要么:
ls ./*
在某些命令中(对于没关系ls),第二个命令更可取,因为即使使用了--一些文件名,它们也可能会被特殊对待。-对于大多数文本实用程序而言,情况就是这样,cd并且pushd包含例如=字符的文件名也是如此awk。./在所有参数之前加上它们将删除其特殊含义(至少对于上述情况而言)。
还应当指出的是,大部分炮弹有一些影响的通配符行为的选项(如点文件是否被忽略与否,排序顺序,做什么,如果没有匹配...),也见$FIGNORE参数ksh
此外,在每一个外壳,但csh,tcsh,fish和zsh,如果文件名匹配模式不匹配任何文件,该模式被作为引起混乱,并可能错误未扩展参数传递。例如,如果当前目录中没有非隐藏文件
ls *
实际上会调用ls两个参数ls和*。而且由于根本没有文件,因此也没有任何文件*,您会看到ls(不是shell)发出的错误消息,例如:ls: cannot access *: No such file or directory,它使人们认为这ls实际上是在扩展全局范围。
在以下情况下,问题甚至更严重:
rm -- *.[ab]
如果没有*.a,也没有*.b文件在当前目录下,那么你可能最终删除一个名为*.[ab]错误(csh,tcsh,和zsh将报告不匹配错误,并不会要求rm(和fish不支持[...]通配符))。
如果确实要将文字传递*给ls,则必须以或或的*某种方式引用该字符。在类似POSIX的shell中,可以使用或一起禁用globing (除非在/ 仿真中,否则后者不起作用)。ls \*ls '*'ls "*"set -o noglobset -fzshshksh
¹尽管(*/)#一直受到支持,但它首先像..../zsh-2.0(甚至可能在以前)中是简写****/形式,然后是2.1 ,然后在2.2中获得确定的形式**/(1992年初)
find -name *。特别是使用更复杂的模式时,如果当前目录中只有一个匹配项,人们通常不会意识到他们没有将星号传递给find。
*.[ab]将尝试删除以结尾的所有内容.[ab]。[鱼不是特别的。
该命令ls默认为ls .:列出当前目录中的所有条目。
该命令的ls *意思是“在*shell模式的扩展上运行ls ”
该*模式由外壳程序处理,并扩展到当前目录中的所有条目,但以.。开头的条目除外。它将深入一层。
双重或三重*模式的解释取决于实际使用的外壳。
*是匹配0个或多个字符的通配符。一些现代的shell将在看到**模式后递归到子目录中。
* 功能外,请参阅其他答案来解释globstar。还应该明确的是,ls 与星号无关,它根本没有经过任何这些星号。运行echo ls *以查看编写时将执行的操作ls *。
您可以通过键入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是您的外壳程序-大多数人都是这样,并且不同的外壳程序具有不同的行为。如果您使用ash或csh或ksh或zsh,则可能会期望事情有所不同。这就是拥有不同外壳的要点。
因此,让我们尝试一些不同的事情(仍然使用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目录。
bash是外壳程序”←,并且未启用globstar。shopt -s globstar然后再试一次...
set -x,它将开始打印每次执行的“实际”命令(使用关闭set +x)。
在某些shell中,包括globstar启用了该选项的bash 4.x ,**将执行递归glob,降级匹配的目录。其他星号不会进一步修改此操作。
ksh93和相反zsh,bash它确实会遍历递归中的符号链接,这通常是不希望的。