ls * 、 ls ** 和 ls *** 的结果

ls * 、 ls ** 和 ls *** 的结果

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

答案1

ls列出作为参数传递的文件和目录内容,如果未给出参数,则列出当前目录。它还可以传递一些影响其行为的选项(请参阅 参考资料man ls详细信息)。

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

然而如果ls *是一个命令行,即使用 Unix shell 语言编写的代码,那么 shell 将*根据其扩展它通配(也称为文件名生成或者文件名/路径名扩展)规则。

虽然不同的 shell 支持不同的通配运算符,但大多数都同意最简单的一种**as 模式表示任意数量的字符,因此*as aglob将扩展到当前目录中与该模式匹配的文件列表。但有一个例外,.文件名中的前导点 ( ) 字符必须显式匹配,因此实际上扩展到不以(按词汇顺序)*开头的文件和目录列表。.

例如,如果当前目录包含名为....foo-l的文件foo bar,则*shell 会将其扩展为两个参数以传递给ls:-lfoo bar,因此就像您键入了:

ls -l "foo bar"

或者

'ls' "-l" foo\ bar

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

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

现在,正如我所说,不同的 shell 有不同的通配符。几十年前,zsh引入了**/运算符 1,它的意思是匹配任何级别的子目录,它是(*/)#和 的缩写***/,除了在目录下降时遵循符号链接之外,它是相同的。

几年前(2003 年 7 月,ksh93o+),ksh93决定复制该行为,但决定将其设为可选,并且仅涵盖案例**(不是***)。另外,虽然**alone 在 ² 中并不特殊(只是与其他传统 shell 中的含义zsh相同,因为表示任意数量的字符后跟任意数量的字符),但在 ksh93 中,其含义与(因此当前当前目录下的任何文件或目录)相同。一个(不包括隐藏文件)³。*******/*

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

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

也支持**.与 的早期版本一样bash,它在目录树下降时遵循符号链接。然而,在那个 shell 中**/*并不相同**。更多的是可以跨多个目录**的扩展。*其中fish**/*.c将匹配a/b/c.c但不匹配a.c,而a**.c将匹配a.c并且例如必须写为ab/c/d.cand 。在那里,被理解为后面跟着所以与 相同。zsh**/.*{,**/}.*********

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

因此,在tcsh, bashand ksh93, (当启用相应选项 ( globstar) 时)或fish**展开当前文件和目录下的所有文件和目录,并且与for***相同,遍历with的符号链接,并且与and中相同(尽管它是这些 shell 的未来版本也可能会遍历符号链接)。**fish**tcshglobstar*bashksh93

在上面,您会注意到需要确保没有任何扩展被解释为选项。为此,你会这样做:

ls -- *

或者:

ls ./*

有一些命令(对于 无关紧要ls),其中第二个命令更可取,因为即使--某些文件名也可能会被特殊处理。-对于大多数文本实用程序cdpushd包含该=字符的文件名awk来说都是这种情况。添加./到所有参数之前会删除它们的特殊含义(至少对于上述情况)。

还应该注意的是,大多数 shell 有许多影响通配行为的选项(例如是否忽略点文件、排序顺序、如果不匹配该怎么办...),另请参阅$FIGNORE中的参数ksh

csh另外,在除、tcshfish和 之外的每个 shell 中zsh,如果通配模式不匹配任何文件,该模式作为未扩展的参数传递,这会导致混乱和可能的错误。例如,如果当前目录中没有非隐藏文件

ls *

实际上将ls使用两个参数ls和进行调用*。由于根本没有文件,所以*也没有人调用,您会看到一条错误消息LS(不是外壳)如:ls: cannot access *: No such file or directory,众所周知,它会让人们认为它ls实际上是在扩展球体。

在以下情况下问题会更加严重:

rm -- *.[ab]

如果当前目录中没有*.anor文件,那么您最终可能会删除一个错误调用的文件(,,并且会报告*.b*.[ab]cshtcshzsh不匹配错误并且不会调用rm(并且fish不支持[...]通配符))。

如果您确实想将文字传递*ls,则必须*以某种方式引用该字符,如ls \*orls '*'ls "*"。在类似 POSIX 的 shell 中,可以使用set -o noglobor完全禁用通配符set -f(后者在zshexcept in sh/ kshemulation 中不起作用)。


1 虽然始终受到支持,但它首先在 zsh-2.0(可能还有之前)中(*/)#出现人手不足的情况,然后在 2.1 中出现,然后在 2.2 中得到其最终形式(1992 年初)..../****/**/

² 的globstarshort选项,此后被添加(2015 年)以允许使用**和分别代替和*****/****/*

³ 另请参阅ksh93globstar设计中还有一些奇怪的地方,其中一些被复制bash

答案2

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

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

*模式由 shell 处理,并扩展到当前目录中的所有条目,除了那些以..它将深入一层。

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

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

答案3

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

所以没有改变。这假设您正在使用bashshell - 大多数人都是如此,并且不同的 shell 有不同的行为。如果您使用ashorcshkshor zsh,您可能会期望事情会有所不同。这就是拥有不同外壳的意义所在。

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

$ 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每个用户的目录。

答案4

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

find . -ls

“find”将深入到目录树的底部(就像“ls -R”一样),并且有更多选项,例如列出目录(-type d)、仅文件(-type f)或显示具有其他内容的文件特征(/etc/passwd 中没有用户、特定权限等等)。 “find”在脚本编写中也更安全(由于 shell 之间的通配规则不一致,以及具有破折号的文件的特殊转义等)。

shell 通配符通配符不能仅与点文件上的星号“*”一起使用。要仅列出点文件,请使用:

ls .??*

相关内容