Kei*_*son 92
该a*
和*a*
语法是由shell实现的,而不是由ls
命令。
当你输入
ls a*
Run Code Online (Sandbox Code Playgroud)
在您的 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
Run Code Online (Sandbox Code Playgroud)
它可能会失败,因为它*.log.bak
是根据当前目录中已经存在的文件展开的。有一些命令可以做这种事情,但它们必须使用自己的语法来指定如何重命名文件。一些命令(如find
)可以做自己的通配符扩展;你必须引用参数来抑制 shell 的扩展:
find . -name '*.txt' -print
Run Code Online (Sandbox Code Playgroud)
shell 的通配符扩展完全基于命令行参数的语法和现有文件集。它不能用命令的含义而受到影响。例如,如果要将所有.log
文件向上移动到父目录,则可以键入:
mv *.log ..
Run Code Online (Sandbox Code Playgroud)
如果您忘记了..
:
mv *.log
Run Code Online (Sandbox Code Playgroud)
并且.log
当前目录中恰好有两个文件,它将扩展为:
mv one.log two.log
Run Code Online (Sandbox Code Playgroud)
这将重命名one.log
和破坏two.log
。
编辑:经过 52 次投票、接受和 Guru 徽章后,也许我应该真正回答标题中的问题。
该-d
或--directory
选项ls
没有告诉它只是列出目录。它告诉它像它们本身一样列出目录,而不是它们的内容。如果您将目录名称作为参数提供给ls
,默认情况下它将列出目录的内容,因为这通常是您感兴趣的内容。该-d
选项告诉它只列出目录本身。这在与通配符结合使用时特别有用。如果您键入:
ls -l a*
Run Code Online (Sandbox Code Playgroud)
ls
会给你的每一个长列表文件的名字开始与a
和的,在内容的每个名字开始与目录a
。如果您只想要文件和目录的列表,每行一行,您可以使用:
ls -ld a*
Run Code Online (Sandbox Code Playgroud)
这相当于:
ls -l -d a*
Run Code Online (Sandbox Code Playgroud)
再次记住,该ls
命令永远不会看到该*
字符。
至于记录在哪里,man ls
将向您展示该ls
命令在几乎任何类 Unix 系统上的文档。在大多数基于 Linux 的系统上,该ls
命令是 GNU coreutils 包的一部分;如果你有info
命令,要么info ls
或info coreutils ls
应该给你更明确和全面的文档。其他系统,如MacOS,可能会使用不同版本的ls
命令,也可能没有info
命令;对于这些系统,请使用man ls
. 如果您使用的是 GNU coreutils 实现,并且ls --help
会显示一个相对较短的使用消息(在我的系统上为 117 行)。
是的,即使是专家也需要不时查阅文档。另见这个经典笑话。
chi*_*rlu 27
见基思汤普森的回答;但要解释为什么ls --directory a*
显示文件和目录:该--directory
选项不抑制非目录文件。相反,它会按原样列出目录,否则会列出它们的内容。例子:
$ mkdir foo
$ touch foo/bar
$ ls foo
bar
$ ls --directory foo
foo
Run Code Online (Sandbox Code Playgroud)
非常明确,它记录在ls(1) 手册页中:
-d, --directory 列出目录条目而不是内容,并且不要取消引用符号链接
公平地说,“条目而不是内容”可能更具解释性:
如果 FILE 是目录,则显示目录条目本身而不是列出该目录的内容。如果 FILE 是符号链接,则显示链接条目本身而不是链接指向的文件。