使用PowerShell循环遍历目录中的文件

341
我该如何修改以下代码以查看目录中的所有.log文件,而不仅仅是一个文件?
我需要循环遍历所有文件并删除所有不包含"step4"或"step9"的行。目前这将创建一个新文件,但我不知道如何在这里使用for each循环(新手)。
实际文件的名称类似于:2013 09 03 00_01_29.log。我希望输出文件要么覆盖它们,要么具有相同的名称,附加"out"。
$In = "C:\Users\gerhardl\Documents\My Received Files\Test_In.log"
$Out = "C:\Users\gerhardl\Documents\My Received Files\Test_Out.log"
$Files = "C:\Users\gerhardl\Documents\My Received Files\"

Get-Content $In | Where-Object {$_ -match 'step4' -or $_ -match 'step9'} | `
Set-Content $Out
4个回答

493

试一下这个:

Get-ChildItem "C:\Users\gerhardl\Documents\My Received Files" -Filter *.log | 
Foreach-Object {
    $content = Get-Content $_.FullName

    #filter and save content to the original file
    $content | Where-Object {$_ -match 'step[49]'} | Set-Content $_.FullName

    #filter and save content to a new file 
    $content | Where-Object {$_ -match 'step[49]'} | Set-Content ($_.BaseName + '_out.log')
}

BaseName 部分无法工作(版本 1)- 但我通过先创建完整文件的备份,然后对原始文件进行更改来解决了这个问题。谢谢。 - user2725402
7
对于v1版本,您可以使用以下语句来提取基本名称:[io.path]::GetFileNameWithoutExtension($name)。 - Shay Levy
1
如果我将“BaseName”替换为“FullName”,我就能得到我想要的结果。 - M--

142

要获取目录的内容,可以使用以下代码:

$files = Get-ChildItem "C:\Users\gerhardl\Documents\My Received Files\"

那么你也可以遍历这个变量:

for ($i=0; $i -lt $files.Count; $i++) {
    $outfile = $files[$i].FullName + "out" 
    Get-Content $files[$i].FullName | Where-Object { ($_ -match 'step4' -or $_ -match 'step9') } | Set-Content $outfile
}

更简单的方法是使用foreach循环(感谢@Soapy和@MarkSchultheiss):

foreach ($f in $files){
    $outfile = $f.FullName + "out" 
    Get-Content $f.FullName | Where-Object { ($_ -match 'step4' -or $_ -match 'step9') } | Set-Content $outfile
}

这会创建一个名为“out.log”的输出文件。我如何为每个输入文件创建单独的输出文件? - user2725402
@user2725402 我添加了一个名为<input file name>out的输入依赖输出文件。 - PVitt
1
好的,有两个新问题...现在由于某种原因它与匹配相反,即它创建一个仅包含不包含“step4”或“step9”的记录的文件。此外,它使用“out”作为扩展名进行重命名,因此文件被命名为“XXX.log.out”-我尝试使用BaseName但无法正确使用。 - user2725402
4
你也可以使用 foreach ($f in Get-ChildItem "C:\Users\gerhardl\Documents\My Received Files\") { ... } 进行操作。 - Soapy
2
请使用以下代码:ForEach ($f in $files){...} - Mark Schultheiss
显示剩余3条评论

46
如果需要递归循环遍历一个目录中特定类型的文件,可以使用以下命令,该命令会过滤所有的doc文件类型:
$fileNames = Get-ChildItem -Path $scriptPath -Recurse -Include *.doc 如果需要对多个类型进行过滤,请使用以下命令: $fileNames = Get-ChildItem -Path $scriptPath -Recurse -Include *.doc,*.pdf 现在,$fileNames变量充当了一个数组对象,您可以循环并应用自己的业务逻辑。

5
让我感到不满的是隐含和/或系统文件的省略。要查看它们,您需要使用“-Force”参数来运行Get-ChildItem命令。请参阅https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-childitem?view=powershell-7上的文档。 - til_b
注意:Include参数仅在命令包括Recurse参数或路径导致目录内容时才起作用(https://dev59.com/CVgR5IYBdhLWcg3wH6Zr#41700792) - Design.Garden

-18
其他答案都很好,我只想补充一下...在PowerShell中可用的不同方法: 安装GNUWin32工具并使用grep查看行/将输出重定向到文件http://gnuwin32.sourceforge.net/ 每次都会覆盖新文件:
grep "step[49]" logIn.log > logOut.log 

如果您覆盖了logIn文件并希望保留数据,则可以将日志输出附加到该文件中:

grep "step[49]" logIn.log >> logOut.log 

注意:要能够全局使用GNUWin32工具,您需要将bin文件夹添加到系统路径中。

27
这个问题被标记为 PowerShell,而不是 Unix。 - SteveC
2
当然。我的看法很简单:你可以在Windows中使用GNUWin32工具,因此你可以轻松地在Powershell中使用*nix工具。这是可行的。没有人说答案必须完全是Powershell本地的。即使他们这样说了,你仍然可以直接从Powershell调用Win32 Utils。据我所知,使用任何可用和兼容的工具实际上并不是一件坏事。 - user1628658
3
我本来想编辑我的先前评论,但我超过了5分钟的限制:SteveC: 你是在说,在Windows中使用运行良好的GNU工具会违背Powershell吗?这是一件事。我明白纯粹使用Powershell解决这个问题可能更有生产力。长期来看,扩展可能性实际上更有价值。你增加了更多选项,并且完全在Windows和Powershell中工作,而没有像Cygwin这样的Linux模拟器。因此,虽然我理解你的顾虑,但我不同意。 - user1628658
8
问题是关于在PowerShell中查找,而不是使用其他可能的语言。 - SteveC
我之前没有注意到你的回复。让我重申一下:你不需要使用不同的语言。GNU Win32Utils 在 CMD 和 PowerShell 中都可以完美地工作。同一种语言,不同的“包含”。GNU Win32Utils 旨在在 Windows 中使用。如果你第三次还是无法理解,我想我就不会再费心了。 - user1628658
6
答案应该是回答问题。这个问题明确要求使用PowerShell回答。你的答案是安装某个东西并使用它。你本可以建议安装Ruby等。 - SteveC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接