我知道使用该命令ls
会列出所有目录。但是该ls *
命令有什么作用呢?我用过它,它只列出了目录。前面的星号是否ls
意味着它将列出目录的深度?
答案1
ls
列出作为参数传递的文件和目录内容,如果未给出参数,则列出当前目录。它还可以传递一些影响其行为的选项(请参阅 参考资料man ls
详细信息)。
如果ls
传递一个名为 的参数*
,它将查找*
当前目录中调用的文件或目录,并像其他任何文件或目录一样列出它。ls
不会*
以任何其他方式对待角色。
然而如果ls *
是一个壳命令行,即使用 Unix shell 语言编写的代码,那么 shell 将*
根据其扩展它通配(也称为文件名生成或者文件名/路径名扩展)规则。
虽然不同的 shell 支持不同的通配运算符,但大多数都同意最简单的一种*
。*
as 模式表示任意数量的字符,因此*
as aglob
将扩展到当前目录中与该模式匹配的文件列表。但有一个例外,.
文件名中的前导点 ( ) 字符必须显式匹配,因此实际上扩展到不以(按词汇顺序)*
开头的文件和目录列表。.
例如,如果当前目录包含名为.
、..
、.foo
和-l
的文件foo bar
,则*
shell 会将其扩展为两个参数以传递给ls
:-l
和foo 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 中,其含义与(因此当前当前目录下的任何文件或目录)相同。一个(不包括隐藏文件)³。*
**
**
**/*
bash
ksh93
几年后复制(2009 年 2 月,bash 4.0),具有相同的语法,但有一个不幸的区别: bash 的**
类似于zsh
s ***
,也就是说,它在递归到子目录时遵循符号链接,这通常不是您想要的,并且可能会产生令人讨厌的副作用。它在 bash-4.3 中得到了部分修复,因为仍然遵循符号链接,但递归在那里停止。 5.0 中已完全修复。
yash
**
2008年在2.0版本中添加,通过extended-glob
选项启用。它的实现更接近zsh
's,因为它**
本身并不特殊。在版本 2.15 (2009) 中,它添加了***
类似 inzsh
和两个自己的扩展:.**
和.***
在递归时包含隐藏的目录(在 中zsh
,D
全局限定符(如**/*(D)
) 将考虑隐藏文件和目录,但如果您只想遍历隐藏目录而不展开隐藏文件,则需要((*|.*)/)#*
或**/[^.]*(D)
)。
鱼也支持**
.与 的早期版本一样bash
,它在目录树下降时遵循符号链接。然而,在那个 shell 中**/*
并不相同**
。更多的是可以跨多个目录**
的扩展。*
其中fish
,**/*.c
将匹配a/b/c.c
但不匹配a.c
,而a**.c
将匹配a.c
并且例如必须写为ab/c/d.c
and 。在那里,被理解为后面跟着所以与 相同。zsh
**/.*
{,**/}.*
***
**
*
**
tcsh
在V6.17.01(2010年5月)中还添加了一个globstar
选项,并且支持**
和***
à la zsh
。
因此,在tcsh
, bash
and ksh93
, (当启用相应选项 ( globstar
) 时)或fish
,**
展开当前文件和目录下的所有文件和目录,并且与for***
相同,遍历with的符号链接,并且与and中相同(尽管它是这些 shell 的未来版本也可能会遍历符号链接)。**
fish
**
tcsh
globstar
*
bash
ksh93
在上面,您会注意到需要确保没有任何扩展被解释为选项。为此,你会这样做:
ls -- *
或者:
ls ./*
有一些命令(对于 无关紧要ls
),其中第二个命令更可取,因为即使--
某些文件名也可能会被特殊处理。-
对于大多数文本实用程序cd
和pushd
包含该=
字符的文件名awk
来说都是这种情况。添加./
到所有参数之前会删除它们的特殊含义(至少对于上述情况)。
还应该注意的是,大多数 shell 有许多影响通配行为的选项(例如是否忽略点文件、排序顺序、如果不匹配该怎么办...),另请参阅$FIGNORE
中的参数ksh
csh
另外,在除、tcsh
、fish
和 之外的每个 shell 中zsh
,如果通配模式不匹配任何文件,该模式作为未扩展的参数传递,这会导致混乱和可能的错误。例如,如果当前目录中没有非隐藏文件
ls *
实际上将ls
使用两个参数ls
和进行调用*
。由于根本没有文件,所以*
也没有人调用,您会看到一条错误消息LS(不是外壳)如:ls: cannot access *: No such file or directory
,众所周知,它会让人们认为它ls
实际上是在扩展球体。
在以下情况下问题会更加严重:
rm -- *.[ab]
如果当前目录中没有*.a
nor文件,那么您最终可能会删除一个错误调用的文件(,,并且会报告*.b
*.[ab]
csh
tcsh
zsh
不匹配错误并且不会调用rm
(并且fish
不支持[...]
通配符))。
如果您确实想将文字传递*
给ls
,则必须*
以某种方式引用该字符,如ls \*
orls '*'
或ls "*"
。在类似 POSIX 的 shell 中,可以使用set -o noglob
or完全禁用通配符set -f
(后者在zsh
except in sh
/ ksh
emulation 中不起作用)。
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
所以没有改变。这假设您正在使用bash
shell - 大多数人都是如此,并且不同的 shell 有不同的行为。如果您使用ash
orcsh
或ksh
or 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 .??*