Answers:
该a*
和*a*
语法是由shell实现的,而不是由ls
命令。
当您键入
ls a*
在您的shell提示符下,shell扩展a*
到当前目录中所有现有文件的列表,其名称以开头a
。例如,它可以扩展a*
为序列a1 a2 a3
,并将其作为参数传递给ls
。该ls
命令本身不会看到*
角色; 它只能看到三个参数a1
,a2
和a3
。
出于通配符扩展的目的,“文件”是指当前目录中的所有实体。例如,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实现。
是的,甚至专家也需要不时查阅文档。另请参阅这个经典笑话。
a*
扩展到当前目录中以开头的所有文件的列表a
。
ls subdir/a*
echo
它。因此,如果您想知道ls a*
执行操作时发生的情况,请首先执行echo ls a*
echo a*
...壳还是反而会膨胀
shopt -s failglob
导致相同的行为。设置nullglob
但不会failglob
导致例如*nosuchfile*
扩展为空字符串。
参见基思·汤普森的答案;但要解释为什么ls --directory a*
显示文件和目录:该--directory
选项不会取消显示非目录文件。相反,它将按原样列出目录,否则将列出其内容。例:
$ mkdir foo
$ touch foo/bar
$ ls foo
bar
$ ls --directory foo
foo
-F
选项更具吸引力
明确地说,它记录在ls(1)手册页中:
-d,-- directory列出目录条目而不是目录,并且不取消引用符号链接
公平地说,“输入而不是内容”可能更具解释性:
如果FILE是目录,请显示目录条目本身,而不要列出该目录的内容。如果FILE是符号链接,请显示链接条目本身而不是链接指向的文件。
如前所述,扩展*
(和类似的扩展)glob
在Unix术语中称为bing,通常是命令处理器的功能(在Unix中被称为“ shell”)。因此,globbing也可以在其他许多地方使用;man 7 glob
在经典Linux发行版的shell上键入(或参见this)以获取关于glob
bing的更多信息。
在早期的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
更改此行为,仅显示目录名称本身,就像对标准文件所做的那样。
文档没有说它仅列出目录条目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 /
该文档是外壳的一部分。特别是,shell 在执行命令之前按特定顺序执行各种扩展和替换。
因此,该ls
命令甚至看不到*
字符,参数已被扩展为与a*
glob模式匹配的所有文件。这与Windows不同,在Windows中,每个需要文件名遍历的命令都必须自己实现此功能。
您需要的关键字(man bash
)是“路径名扩展”。