命令“ls .*”和“ls *.”的不同输出

cri*_*ron 3 ls shell wildcards

命令

    ls .*
Run Code Online (Sandbox Code Playgroud)

当运行给出以下输出时:

  • 当前目录中的所有文件以 . (隐藏文件)
  • 当前目录中存在的隐藏目录中的所有文件
  • 当前目录下的所有文件
  • 父目录下的所有文件

为什么命令

    ls *.
Run Code Online (Sandbox Code Playgroud)

不显示:

  • 当前目录下的所有文件
  • 父目录下的所有文件

我这么想的原因是:正则表达式 *. 应该匹配两者。和 .. So ls 应该在两者上运行,因此应该显示我期望的输出

ter*_*don 8

这是因为默认情况下*不匹配以 a 开头的文件.。考虑以下目录:

$ ls -la 
total 8404
drwxrwxrwx   2 terdon terdon 8105984 Dec 31 13:14 .
drwxr-xr-x 153 terdon terdon  491520 Dec 30 22:32 ..
-rw-r--r--   1 terdon terdon       0 Dec 31 13:14 .dotfile
-rw-r--r--   1 terdon terdon       0 Dec 31 13:14 file1
-rw-r--r--   1 terdon terdon       0 Dec 31 13:14 file2
-rw-r--r--   1 terdon terdon       0 Dec 31 13:14 file3.
Run Code Online (Sandbox Code Playgroud)

让我们看看您使用的每个 glob 扩展为:

$ echo .*
. .. .dotfile

$ echo *.
file3.

$ echo *
file1 file2 file3.
Run Code Online (Sandbox Code Playgroud)

如您所见,*不包括以.so开头的文件或目录,./并且../都被忽略。你的ls例子也会发生同样的事情。在 中bash,您可以使用dotglob参数更改此设置,这也将导致*扩展为点文件(但不能扩展为...,它们仍然会被忽略):

$ shopt -s dotglob
$ echo *
.dotfile
Run Code Online (Sandbox Code Playgroud)

其他壳的行为不同。例如,在使用时zsh也忽略.和:...*

% echo .*
.dotfile
Run Code Online (Sandbox Code Playgroud)


Mat*_*Mat 5

文件名扩展规则有一个特殊情况,.作为文件名中的第一个字符:它必须显式匹配(即模式必须包含一个开始.,或.在 a 之后/)。否则这些文件不是候选文件。

这就是为什么您的第一个版本确实会选择以 开头的文件名.,而第二个版本则不会。*.文件名的第一个字符不匹配。

POSIX Shell 命令语言将其描述为:

如果文件名以句点 ( '.' ) 开头,则应通过使用句点作为模式的第一个字符或紧跟斜杠字符来显式匹配句点。领先期不得与:

  • 星号或问号特殊字符
  • 包含非匹配列表的括号表达式,例如“[!a]”,范围表达式,例如“[%-0]”,或字符类表达式,例如“[[:punct:]]”

未指定括号表达式匹配列表中的显式句点(例如“[.abc]”)是否可以匹配文件名中的前导句点。

您的 shell 可能具有更改此行为的选项。例如,Bash 有这个(文件名扩展):

当模式用于文件名扩展时,字符 '.' 除非设置了 shell 选项 dotglob,否则在文件名的开头或紧跟在斜杠后面的必须显式匹配。匹配文件名时,必须始终明确匹配斜杠字符。在其他情况下,“.” 字符没有被特殊对待。


请注意,这些不是正则表达式。.*因为正则表达式可以匹配任何东西(包括什么都不匹配)。*.将是畸形的。