为什么ls -d也列出文件,并且在哪里记录?


48
  • 指定时ls --directory a*,应仅列出以a*
  • 但它会列出文件和目录以 a

问题

  • 除了我认为应该彻底查找的地方以外maninfo在哪里可以找到有关此内容的文档?
  • 这仅在BASH中有效吗?


5
echo a*还会列出您以a(开头)开头的文件。为了更清楚地说,它不是ls在执行此操作,而是在执行bash。
ash108年

Answers:


89

a**a*语法是由shell实现的,而不是由ls命令。

当您键入

ls a*

在您的shell提示符下,shell扩展a*到当前目录中所有现有文件的列表,其名称以开头a。例如,它可以扩展a*为序列a1 a2 a3,并将其作为参数传递给ls。该ls命令本身不会看到*角色; 它只能看到三个参数a1a2a3

出于通配符扩展的目的,“文件”是指当前目录中的所有实体。例如,a1可能是普通文件,a2可能是目录,也a3可能是符号链接。它们都具有目录条目,而Shell的通配符扩展并不关心这些条目所指的是哪种实体。

实际上,您可能遇到的所有shell(bash,sh,ksh,zsh,csh,tcsh等)都实现了通配符。细节可能有所不同,但是*匹配零个或多个字符以及?匹配任何单个字符的基本语法是相当一致的。

特别是对于bash,它记录在bash手册的“文件名扩展”部分;运行info bash并搜索“文件名扩展”,或在此处查看

这是由Shell而不是由单个命令完成的事实,会带来一些有趣的(有时是令人惊讶的)后果。最好的是,通配符处理对于(几乎)所有命令都是一致的。如果shell不这样做,那么不可避免地有些命令将不会打扰,而另一些命令则会以作者认为更好的不同方式来执行。(我认为Windows命令外壳程序存在此问题,但我对其不够熟悉,无法进一步评论。)

另一方面,编写重命名多个文件的命令很困难。如果您写:

mv *.log *.log.bak

由于*.log.bak基于当前目录中已经存在的文件进行了扩展,因此它可能会失败。有些命令可以执行这种操作,但是它们必须使用自己的语法来指定如何重命名文件。有些命令(例如find)可以执行自己的通配符扩展;您必须引用参数以禁止外壳扩展:

find . -name '*.txt' -print

Shell的通配符扩展完全基于命令行参数和现有文件集的语法。它不能用命令的含义而受到影响。例如,如果要将所有.log文件上移到父目录,则可以键入:

mv *.log ..

如果您忘记了..

mv *.log

并且.log当前目录中恰好有两个文件,它将扩展为:

mv one.log two.log

这将重命名one.log和破坏two.log

编辑:在52次投票,一个接受和一个Guru徽章之后,也许我应该真正回答标题中的问题。

-d--directory选项ls不会告诉它仅列出目录。它告诉它列出目录的方式与它们本身相同,而不是目录内容。如果将目录名作为参数ls的默认值,它将默认列出目录的内容,因为这通常是您感兴趣的内容。该-d选项告诉它仅列出目录本身。与通配符结合使用时,这尤其有用。如果输入:

ls -l a*

ls将给您列出名称以开头的每个文件a以及名称以开头的每个目录的内容的长清单a。如果只需要文件和目录的列表(每行一个),则可以使用:

ls -ld a*

等效于:

ls -l -d a*

再次记住该ls命令永远看不到*字符。

至于该文件的记录位置,man ls将向您显示该ls命令在几乎所有类Unix系统上的文档。在大多数基于Linux的系统上,该ls命令是GNU coreutils软件包的一部分;如果您有此info命令,则应该info ls或者info coreutils ls应该给您更多权威的文档。其他系统,例如MacOS,可能使用该ls命令的不同版本,并且可能没有该info命令。对于那些系统,请使用man ls。并ls --help会显示一个比较简短的用法消息(117线我的系统上),如果您使用的GNU的coreutils实现。

是的,甚至专家也需要不时查阅文档。另请参阅这个经典笑话


8
@Thomas:a*扩展到当前目录中以开头的所有文件的列表a
基思·汤普森

2
@Thomas:或在您指定的任何目录中:ls subdir/a*
Keith Thompson

1
要真正看到shell扩展后执行的命令,echo它。因此,如果您想知道ls a*执行操作时发生的情况,请首先执行echo ls a*
CarlosCampderrós13年

1
还是只是echo a*...壳还是反而会膨胀
没用,

2
@sendmoreinfo:这取决于外壳和设置。在csh和tcsh中,全局扩展失败是一个错误。在bash中,shopt -s failglob导致相同的行为。设置nullglob但不会failglob导致例如*nosuchfile*扩展为空字符串。
基思·汤普森

27

参见基思·汤普森的答案;但要解释为什么ls --directory a*显示文件目录:该--directory选项不会取消显示非目录文件。相反,它将按原样列出目录,否则将列出其内容。例:

$ mkdir foo
$ touch foo/bar
$ ls foo
bar
$ ls --directory foo
foo

3
该示例对该-F选项更具吸引力
glenn jackman 2013年

6

明确地说,它记录在ls(1)手册页中

-d,-- directory列出目录条目而不是目录,并且不取消引用符号链接

公平地说,“输入而不是内容”可能更具解释性:

如果FILE是目录,请显示目录条目本身,而不要列出该目录的内容。如果FILE是符号链接,请显示链接条目本身而不是链接指向的文件。


为方便起见,虽然-d选项可以在手册页中进行说明(如果简洁的话),但参数扩展和通配符未在ls手册页中记录,因为它是由Shell完成的。如果您在外壳程序中关闭了文件名扩展,则“ ls a *”将仅显示一个字面名为“ a *”的文件。
约翰尼,

令人讨厌的是,尽管其他受访者回答了外壳扩展的问题,但他们都没有解决解释不充分的问题以及可能会被误读的问题。如果您希望我重复已经讲得很清楚的内容,请更加直接。
msw

4

乱语

如前所述,扩展*(和类似的扩展)glob在Unix术语中称为bing,通常是命令处理器的功能(在Unix中被称为“ shell”)。因此,globbing也可以在其他许多地方使用;man 7 glob在经典Linux发行版的shell上键入(或参见this)以获取关于globbing的更多信息。

在早期的Unix中,glob实际上是由称为的单独程序实现的/etc/glob(有关说明的文档,请参阅此旧UNIX手册的第10页)。如今,它是由代码库提供的代码例程,并且通常由Shell使用。资料来源维基百科

目录

至于为什么ls -d列出文件和目录...

ls手册页解释了为什么出现这种情况,但有一个非常简洁的解释。因此,这里尝试扩展解释:

默认情况下,ls列出目录的内容(给定名称)后,将对目录的符号链接执行相同的操作。该-d选项意味着,“给定的目录(IES)的姓名(或名称)时”(这也可以给予隐含glob冰),只显示目录(IES)的_name_s,但不是它们的内容。类似地,当为目录提供符号链接的(显式或隐式)名称时,请显示符号链接的文件名,而不是其引用目录的内容。

-d据我所知,该选项与列出哪些项目无关。可以使用来完成此操作(来源:此处find,如下所示:find . -maxdepth 1 -type d。我不确定仅使用GNU是否有一个好的方法ls以下是一些有关如何使用find命令的示例。

总结一下:默认情况下ls,给定目录的路径名时将显示目录的内容。-d更改此行为,仅显示目录名称本身,就像对标准文件所做的那样。


3

文档没有说它列出目录条目bur,而是在ls接收目录名称时列出目录条目而不是其内容。最好的理解方式是通过示例:

> {ice} ~ :10:47 % ls -l / 
total 97
drwxr-xr-x   2 root root  4096 May  3 00:27 bin
drwxr-xr-x   4 root root  1024 May  3 14:17 boot
drwxr-xr-x   2 root root  4096 Apr 29 13:44 cdrom
drwxr-xr-x  18 root root  4420 May  9 09:58 dev
...
lrwxrwxrwx   1 root root    33 May  3 14:16 vmlinuz -> boot/vmlinuz-3.9.0-030900-generic
lrwxrwxrwx   1 root root    29 May  3 11:07 vmlinuz.old -> boot/vmlinuz-3.8.0-19-generic
> {ice} ~ :10:47 % ls -ld /
drwxr-xr-x 25 root root 4096 May  3 14:16 /

2

该文档是外壳的一部分。特别是,shell 在执行命令之前按特定顺序执行各种扩展和替换

Bourne兼容shell单词扩展顺序为

  1. 波浪扩展
  2. 参数扩展
  3. 命令替换
  4. 算术扩展
  5. 场分裂
  6. 路径名扩展
  7. 删除报价

因此,该ls命令甚至看不到*字符,参数已被扩展为与a*glob模式匹配的所有文件。这与Windows不同,在Windows中,每个需要文件名遍历的命令都必须自己实现此功能。


1

您需要的关键字(man bash)是“路径名扩展”。


3
更像是“路径名扩展”或“文件名生成”。与“模式匹配”有关,但不相同。
斯特凡Chazelas

@StephaneChazelas确实,但是“模式匹配”是手册页中“路径名扩展”的一个子部分,而“文件名生成”根本就不存在(仅在信息文档中)。
Hauke Laging,
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.