好吧,我就是这样做的,而且看起来很有效。
$files = cmd /c "$GETFILESBAT \\$server\logs\$filemask"
foreach( $f in $files ) {
if( $f.length -gt 0 ) {
select-string -Path $f -pattern $regex | foreach-object { $_ }
}
}
然后 $GETFILESBAT 指向这个:
@dir /a-d /b /s %1
@exit
我正在从 PowerShell 脚本中编写和删除这个 BAT 文件,所以我猜这是一个仅限 PowerShell 的解决方案,但它不仅仅使用 PowerShell。
我的初步性能指标显示速度快了一万倍。
我测试了 gci 与 cmd dir 与来自 @Shawn Melton 引用的 FileIO.FileSystem.GetFileslink http://blogs.msdn.com/b/powershell/archive/2009/11/04/why-is-get-childitem-so-slow.aspx.
最重要的是,对于本地驱动器上的日常使用,GetFiles
是最快的。By far. CMD DIR
是值得尊敬的。一旦您为许多文件引入较慢的网络连接,CMD DIR
略快于GetFiles
. Then Get-ChildItem
...哇,这范围从不太糟糕到可怕,具体取决于所涉及的文件数量和连接速度。
一些测试运行。我在测试中移动了 GCI,以确保结果一致。
10次迭代扫描c:\windows\temp
对于 *.tmp 文件
.\test.ps1 "c:\windows\temp" "*.tmp" 10
GetFiles ... 00:00:00.0570057
CMD dir ... 00:00:00.5360536
GCI ... 00:00:01.1391139
GetFiles 比 CMD dir 快 10 倍,而 CMD dir 本身比 GCI 快 2 倍以上。
10次迭代扫描c:\windows\temp
对于带有递归的 *.tmp 文件
.\test.ps1 "c:\windows\temp" "*.tmp" 10 -recurse
GetFiles ... 00:00:00.7020180
CMD dir ... 00:00:00.7644196
GCI ... 00:00:04.7737224
GetFiles 比 CMD dir 快一点,两者几乎都比 GCI 快 7 倍。
扫描另一个域上的现场服务器以获取应用程序日志文件的 10 次迭代
.\test.ps1 "\\closeserver\logs\subdir" "appname*.*" 10
GetFiles ... 00:00:00.3590359
CMD dir ... 00:00:00.6270627
GCI ... 00:00:06.0796079
GetFiles 比 CMD dir 快大约 2 倍,本身比 GCI 快 10 倍。
扫描另一个域上的远程服务器以查找应用程序日志文件的一次迭代,涉及许多文件
.\test.ps1 "\\distantserver.company.com\logs\subdir" "appname.2011082*.*"
CMD dir ... 00:00:00.3340334
GetFiles ... 00:00:00.4360436
GCI ... 00:11:09.5525579
CMD dir 是到达包含许多文件的远程服务器最快的,但 GetFiles 相当接近。另一方面,GCI 的速度要慢几千倍。
扫描另一个域上的远程服务器以查找应用程序日志文件(包含许多文件)的两次迭代
.\test.ps1 "\\distantserver.company.com\logs\subdir" "appname.20110822*.*" 2
CMD dir ... 00:00:00.9360240
GetFiles ... 00:00:01.4976384
GCI ... 00:22:17.3068616
随着测试迭代的增加或多或少呈线性增加。
扫描另一个域上的远程服务器以查找应用程序日志文件的一次迭代,文件较少
.\test.ps1 "\\distantserver.company.com\logs\othersubdir" "appname.2011082*.*" 10
GetFiles ... 00:00:00.5304170
CMD dir ... 00:00:00.6240200
GCI ... 00:00:01.9656630
这里 GCI 还不错,GetFiles 快了 3 倍,CMD dir 紧随其后。
结论
GCI
需要一个-raw
or -fast
不尝试做太多事情的选项。同时,GetFiles
是一种健康的替代方案,只是偶尔比它慢一点CMD dir
,并且通常更快(由于生成 CMD.exe?)。
作为参考,这里是 test.ps1 代码。
param ( [string]$path, [string]$filemask, [switch]$recurse=$false, [int]$n=1 )
[reflection.assembly]::loadwithpartialname("Microsoft.VisualBasic") | Out-Null
write-host "GetFiles... " -nonewline
$dt = get-date;
for($i=0;$i -lt $n;$i++){
if( $recurse ){ [Microsoft.VisualBasic.FileIO.FileSystem]::GetFiles( $path,
[Microsoft.VisualBasic.FileIO.SearchOption]::SearchAllSubDirectories,$filemask
) | out-file ".\testfiles1.txt"}
else{ [Microsoft.VisualBasic.FileIO.FileSystem]::GetFiles( $path,
[Microsoft.VisualBasic.FileIO.SearchOption]::SearchTopLevelOnly,$filemask
) | out-file ".\testfiles1.txt" }}
$dt2=get-date;
write-host $dt2.subtract($dt)
write-host "CMD dir... " -nonewline
$dt = get-date;
for($i=0;$i -lt $n;$i++){
if($recurse){
cmd /c "dir /a-d /b /s $path\$filemask" | out-file ".\testfiles2.txt"}
else{ cmd /c "dir /a-d /b $path\$filemask" | out-file ".\testfiles2.txt"}}
$dt2=get-date;
write-host $dt2.subtract($dt)
write-host "GCI... " -nonewline
$dt = get-date;
for($i=0;$i -lt $n;$i++){
if( $recurse ) {
get-childitem "$path\*" -include $filemask -recurse | out-file ".\testfiles0.txt"}
else {get-childitem "$path\*" -include $filemask | out-file ".\testfiles0.txt"}}
$dt2=get-date;
write-host $dt2.subtract($dt)