CMD:*。*还是*?


47

早在1990年代,我将使用“ *.*”来表示MS-DOS中的任何文件名,但是*这些天我看到了更多使用“ ”的脚本。我使用哪一个实际上有什么区别?


9
尽管确实如此,*并且*.*现在对于cmd内部命令和现代命令行实用程序来说是等效的,但是某些采用文件掩码参数的较旧的实用程序可能会使用较旧的文件匹配功能,并且对于它们而言,掩码将不等效。
AFH

@AFH我认为令牌不相等。该*.*令牌不应该返回扩展名的文件。
tuskiomi

1
@tuskiomi-我同意您的意见,即*.* 不应返回无扩展名的文件。不幸的是。请参阅Grawity的答案。
AFH

Answers:


65

自Windows 95和NT 3.5引入“长文件名”支持以来,文件名和扩展名一直是一个字段,并且一次对整个文件名进行通配符匹配。结果,您可以使用不带点的文件名(对于文件来说可能很少,但对于文件夹/目录来说很常见),乍一看*.*实际上并不匹配这些文件。

使用旧的脚本*.* 仍然是因为兼容性代码工作-如果通配符结尾.*,这部分是由操作系统忽略。(因此,如果您想使用扩展名专门匹配文件,我想您将需要这样做*.?*。)

但这不是您应该依赖的东西。如果要为现代Windows版本编写脚本,请遵循它们的约定,而不要遵循MS-DOS约定。(请注意,从Windows NT开始,.bat脚本不再由MS-DOS解释,而是由cmd.exe本机Win32程序解释。)


在Linux和其他各种Unixen上,名称和扩展名从来没有分开过,并且没有任何特殊的方法可以*.*工作,所以*唯一有意义的选择是。


14
“让我们更难过滤带有扩展名的文件!是的!” -匿名的Microsoft开发人员
John Hamilton'7

50
“让我们为每个人打破数百万个现有的批处理脚本!是的!” -永远都没有Microsoft开发人员
感激之声

3
ISTR在某些旧版本的DOS上*只能匹配文件名而没有扩展名。两者兼容的“安全”方法是使用**
Random832 '17

8
OP是关于Windows的,但是自从您提到Linux以来:在某些shell(例如Bash)中,*默认情况下)与隐藏的文件名不匹配(以开头.)。
Florian Brucker

4
对于“操作系统级别”的某些值...在Windows中,它实际上也是一个Shell(Explorer)概念–内核不关心可执行文件上的.exe,也不关心任何其他内容。Windows Explorer是否比Linux中的Nautilus更“操作系统级别”。
grawity '17

11

这也许值得一提的是,unixy / posixy炮弹一样的Bourne shell时,bash和ksh,zsh的,等做通配符扩展(全域字符,例如*?[range][!range]和其他扩展像括号和扩展水珠)编译的参数列表的命令被执行。因此,此扩展是由Shell而不是由其作为参数的命令完成的。

即Shell负责什么**.*扩展到

 $ ls
 file.csv  file.doc  file.pdf  file.txt  file.xlsx  zz-file-without-extension

 $ (set -xv; foo *)   # is actually expanded to the following
   + foo file.csv file.doc file.pdf file.txt file.xlsx zz-file-without-extension

 $ (set -xv; foo *.*)  # note this does not match `zz-file-without-extension`
   + foo file.csv file.doc file.pdf file.txt file.xlsx

在CMD中(与Powershell实用程序类似),情况并非如此,因为它会将glob字符逐字传递到执行的命令中-因此扩展是命令/实用程序而不是Shell的责任。因此,最终,该工具留给工具*.**工具以使其符合(或不符合)约定,这就是为什么CMD的工具dir *.*也匹配(可能错误地保留期望)文件而没有扩展名的原因。

我相信以这种方式进行总结是安全的。

  • 在CMD下,它取决于实用程序。
  • 在PowerShell下,利用WildCardPattern 类的实用程序将提供一致的posixy行为子集。

另一个区别是,在CMD下,大多数程序实际上将原始通配符转发到内核(FindFirstFile),而Linux上的glob仅捕获完整列表并在用户空间中进行过滤。
grawity '17

在具有一百万个文件的目录上运行*时,该命令将抱怨参数过多。在最坏的情况下,它可能会悄无声息地落在列表的末尾。在这种情况下,您需要通过管道传递两个或多个命令,或者将文件名列表保存在文件中,以便其他进程可以读取该列表。
恩里克·海军

3
@grawity更准确地说,筛选是由Windows上的文件系统驱动程序完成的。这在网络文件系统上尤其有用(尤其是当您可以在远程文件系统上运行8 kb的行时),但是这也意味着您不能执行任意搜索以及显式支持的搜索。雷蒙德·陈(Raymond Chen)的博客多次探讨了这种含义。FindFirstFile本身是用户模式(kernel32.dll和ntdll.dll都是用户模式库-它是Win32子系统的一部分,而不是内核的一部分),但实际上并没有做什么。
a安

嗯,我的印象是FindFirstFile几乎直接包装了一个类似名称的syscall(就像libc中的open(3)如何在Linux内核中包装open(2)一样)。
grawity

1
@cup:只需使用引号来防止外壳扩展glob,因此可以将其传递给命令。例如 mmv "fred.*" "tom.#1"。(替换使用#1代替*,这具有让您对字段重新排序的优势)。 mmv默认情况下,大多数系统上未安装该工具,但通常会安装其他批处理重命名工具。请参阅有关此文章,以及stackoverflow.com/questions/417916/how-to-do-a-mass-rename
彼得·科德斯
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.