有什么方法可以使Windows cmd shell扩展通配符路径吗?


37

有时,cmd shell无法扩展通配符路径确实会带来不便。我必须将目录中的100个文件传递给程序,并且无法键入* .ext。相反,我使用mingw的'ls'将列表转储到文件中,然后用空格替换换行符,将其复制并粘贴到cmd中。一场噩梦。

我怀疑答案是否定的,但是有没有人处理过这个问题或想出什么方法可以使之更容易?


2
您是否考虑过使用Powershell之类的东西?

I suspect the answer will be no, but has anyone dealt with this or come up with any way to make this easier? 实际上,我遇到了相反的问题,我试图找到一种方法来使命令解释器将其列表视为字符串,并防止其将其替换为通配符。例如,for %i in (foobar baz really?) do @echo %i将视最后一项(really?)作为文件名通配符,并跳过它,如果没有指定的文件really1reallyz等☹
Synetech

1
@Synetech- ?不是Windows文件系统中文件名的合法字符。字符只能解释为通配符。请参阅在MSDN上命名文件,路径和命名空间,以及在TechNet中使用通配符
jww

Answers:


18

DOS以及Windows' cmd.exe都不支持外壳程序通配符扩展。扩展始终取决于应用程序。

这意味着,如果您使用的是不支持扩展的应用程序,则总是必须找到另一条路线。你可以:

  • 使用FOR循环对您感兴趣的所有文件运行一些命令
  • 使用dir /b > list.txt使用dir命令来执行扩张,并把文件的列表到一个文本文件(那么你可以使用像Excel公式,如果你真的绝望产生的命令列表粘贴到cmd,或者你可以使用Excel移调单元格,以便所有文件名都在同一行上。)

他解释说,将dir的结果输出到文件中并手动处理过滤和复制将是一场噩梦。wmz的答案,当然是我的,无需手动过滤文件内容即可使用。
wullxz 2012年

1
@wullxz:也许,但是对于不熟悉Powershell的人,希望一次性完成此操作,它可能会更快-该网站的想法是为各种技能的人们提供有用的解决方案,以便他们现在和以后参考。未来,所以真的不需要告诉我,因为您认为我的回答不如您的回答。
Malvineous

1
“ DOS,因此是Windows的cmd.exe,从不支持Shell进行通配符扩展。” -根据Microsoft的说法,这不是真的。请参阅在TechNet上使用通配符。(但我认为您在实践中是正确的:o。否则,我不会在这里试图找出文件不匹配的原因)
jww 2015年

1
@jww:您发布的链接说明了通配符的标准用法,但是我看不到任何有关它们被外壳扩展的说明。与UNIX(以及后来的Linux和Mac)不同,Microsoft将通配符扩展留给每个单独的应用程序来实现,并按原样传递命令行参数。
Malvineous

1
DOS命令“ dir Filespec / b”的工作原理非常好,因为它创建了文件列表,每行一个。使用附加的“ / s”开关,文件名是完全限定的(绝对的),并且可以很容易地通过for循环提供给其他任何使用文件名的命令行程序。这是我们能做的最好的事情,因为Windows没有适当的浮动功能。
David A. Gray

9

只需使用Windows 7上预装的Powershell,Powershell就能运行cmd命令,并且可以理解路径中任何位置的通配符。

要启动Powershell,只需在开始菜单搜索框中键入“ powershell”,然后按Enter。


如果应用程序期望其中包含所有文件名的字符串,那么这是正确的脚本:

$delimiter = " "
[string]$files = $nothing ; ls *.txt | % { $files += $_.fullname + $delimiter } ; application.exe $files

如果您的应用程序需要逗号分隔的文件名列表,请更改$delimiter = " "$delimiter = ","

代码说明:

  • [string]$files = $nothing -创建一个类型为空的变量 string
  • ; -是多个命令的分隔符,而不是管道!
  • ls *.txt | % { $files += $_.fullname + $delimiter } -获取所有文本文件的列表,并创建一个字符串,其中所有文件名都由定界符分隔
  • application.exe $files -调用应用程序并将文件列表传递给它

您甚至可以通过添加-recurse来递归搜索文件模式,ls *.txt因此完整的代码应如下所示:

$delimiter = " "
[string]$files = $nothing ; ls *.txt -recurse | % { $files += $_.fullname + $delimiter } ; application.exe $files

编辑:
为了避免刺激,ls并且dir是别名Get-ChildItem%是它的别名ForEach-Object。我保留使用别名的代码,因为它更短。

编辑2018/04/25:
早在2012年,我就对PowerShell相当陌生。当然,有一种更简单的方法,尽管它不像unix / linux的glob扩展功能那么简单:

app.exe $(ls *.txt | % {$_.FullName})

说明:

  • $()将首先计算表达式内部的内容,并将其替换为该表达式的输出(就像反引号在bash中一样)
  • ls *.txt 获取与全局匹配的所有文件的FileInfo对象 *.txt
  • 因为PowerShell是面向对象的,所以我们必须输出每个FileInfo对象的全名。默认情况下,只需在PowerShell中命名属性即可。% { $_.FileName }为我们做到了。%循环遍历返回的所有元素ls并输出每个对象FileName。

2
尽管PS当然能够满足要求,但熟悉它的建议是合理的-它并不像您建议的那么简单。运行start notepad++ *.txt(与意向打开所有TEXTFILES -使用记事本+ +,因为它处理多个名称)将让你无处
WMZ

1
您可以使用解决此问题dir *.txt | % { notepad++.exe $_ }。我用简单的记事本尝试了一下,因为我没有记事本++,并且它可以工作。该命令接收当前目录中所有txt文件的列表,将该列表传递给下一个命令,该命令循环遍历该列表,并以文件名作为参数执行notepad ++。
wullxz 2012年

是的,但这不是等效的。考虑grep "a b c"寻找任何列出的字符串,其中“ ab c”将被扩展为列表
wmz 2012年

5
运行命令的项目作为参数的列表是不等同于运行命令与每个元件多次从列表作为参数。另一个示例:copy a+b+c resultcopy a result copy b result copy c result。(和grep之类的实用程序确实存在于PS中,称为select-string
wmz 2012年

1
被投票赞成,顺便说一句,可惜OP不在乎解释一下……
wmz 2012年

8

这将为您提供一个列表,并将其放入名为的变量中expanded_list。将其放在批处理文件中,然后使用运行myBatchFile name myPattern。如果包含空格,请用引号将模式引起来。匹配文件,无目录。不带参数运行将全部匹配。

@echo off
set expanded_list=
for /f "tokens=*" %%F in ('dir /b /a:-d "%~1"') do call set expanded_list=%%expanded_list%% "%%F"

echo expanded_list is: 
echo %expanded_list%

然后可以使用以下命令运行命令 my_command_exec %expanded_list%

警告!cmd变量的最大大小为8191个字符(XP之后),因此有可能溢出!您不能指望该实用程序始终提供完整的列表。另一方面,最大cmd行长度也是8191,因此无论如何您将无法执行它。


请注意,如果未指定任何参数,则expanded_list将被设置为当前目录中所有可能不需要的文件,因此可能希望不添加任何参数进行检查(例如,如果“%1” ==“” ...)
JasonM1 2014年

3

这在cmd.exe中有效

dir /b *.ext

要么

echo | dir /b *.ext

这仅适用于文件名,而不适用于路径的任何部分。例如dir /b TortoiseSVN\bin\sv*.exe将显示svn.exesvnadmin.exe。但是dir /b TortoiseSVN\bi*\svn.exe显示语法错误。
styfle

1
检查dir /s /b。这为您提供了完整的路径。
WesternGun

3

请注意,这是在单独的线程user619818和styfle中对发帖者的注释)

DIR可以并且确实允许在所有子目录中搜索与特定类型匹配的文件。

注意:由于作者没有给出这些目录所在的路径名,因此检查所有子目录都位于其下的Root目录被假定为“ C:\ My Program \ Root \”。

DIR /B /S "C:\My Program\Root\*.ext"

这将提供源文件的完整文件路径和文件名。

如果只需要文件名,则必须执行以下操作

FOR /F "Tokens=*" %A IN ('DIR /B /S "C:\My Program\Root\*.ext"') DO @( Echo.%~nxA )

因此,假设您要将所有这些文件从“ C:\ My Program \ Root \ Sub Directories \ *。ext”移动到“ D:\ Singlefolder \ *。ext”,则只需执行以下操作:

FOR /F "Tokens=*" %A IN ('DIR /B /S "C:\My Program\Root\*.ext"') DO @( MOVE "%~A" "D:\Singlefolder\%~nxA" /Y )

希望将来对其他人有帮助。:)


1

这很旧,但是对于Windows的Linux子系统来说,现在在您的PATH中添加bash相当普遍。如果真是这样,那么这可能为您解决问题:

bash -c 'cat *.txt'

请注意,单引号在Windows cmd中不是特殊的,因此,如果从cmd运行上述命令,它将不起作用。这也适用于具有Cygwin或其他bash环境的系统
phuclv '18
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.