如何在多个文件中搜索字符串并返回文件名(使用Powershell)?

435

我几天前开始学习PowerShell,但我在谷歌上找不到我需要的内容,请耐心看完我的问题。

现在有人让我把一些文本字符串替换到多个文件中。我不知道这些文件的可能扩展名,也不知道它们的位置。到目前为止,我已经成功地使用get-ChildItem -recurse递归浏览了目录,并通过get-content和select-string查找到了我要查找的字符串:

Get-ChildItem -recurse | Get-Content | Select-String -pattern "dummy"

问题是,我能看到包含我要查找的文本的位置,但我不知道如何告诉PS也返回每个匹配文件的路径和名称。

我该如何获取包含我要查找的表达式的文件的名称和位置?


4
也许将问题编辑得更为通用一些会更好。这个问题的答案似乎与JBoss或您正在处理的应用程序无关...... - Kellen Stuart
10
我刚看到你的评论并编辑了我的问题……两年后!迟做总比不做好。 :) - Bluz
12个回答

696

这应该给出包含您的模式的文件的位置:

Get-ChildItem -Recurse | Select-String "dummy" -List | Select Path

3
如果你想移动这些文件怎么办?我使用这个命令出现了错误,无法将“Move-Item”与其结尾处的管道符号“|”连接起来。 - rud3y
6
Move-Item命令没有name参数。尝试添加| %{Move-Item $_.name <destination>}以移动项目到指定目录。 - jon Z
57
Get-ChildItem -Recurse | Select-String "dummy" -List | Select Path 只返回每个文件的第一个匹配项,因此可能更有效率,避免了需要分组的步骤。 - ben
16
值得注意的是,如果您使用“Get-ChildItem -Recurse -Filter *.txt”而不是“Get-ChildItem -Recurse”,则可以仅过滤特定文件类型(例如txt文件)。 - Girardi
2
@rud3y,如果你正在进行大规模操作,我强烈建议你使用“foreach”循环将其写成脚本形式。如果你试图在一行上完成所有这些操作,它会变得非常混乱,并且很容易犯大错。我有经验的人说到了这些。 - Kellen Stuart
显示剩余9条评论

107
这里有很多准确的答案,但以下是几种不同变体的最简洁代码。对于每个变体,顶部显示完整语法,底部显示简洁语法。
项目(2)是Jon Z和manojlds的答案更简洁的形式,而项目(1)等同于vikas368和buygrush的答案。
  1. 列出包含某种模式的所有文件的FileInfo对象:

    <b>Get-ChildItem -Recurse</b> <i>filespec</i> <b>| Where-Object { Select-String</b> <i>pattern</i> <b>$_ -Quiet }</b>
    <b>ls -r</b> <i>filespec</i> <b>| ? { sls</b> <i>pattern</i> <b>$_ -q }</b>
    
  2. 列出包含模式的所有文件名:

  3. <b>Get-ChildItem -Recurse</b> <i>filespec</i> <b>| Select-String</b> <i>pattern</i> <b>| Select-Object -Unique Path</b>
    <b>ls -r</b> <i>filespec</i> <b>| sls</b> <i>pattern</i> <b>| select -u Path</b>
    
  4. 列出不包含模式的所有文件的FileInfo对象:

  5. <b>Get-ChildItem -Recurse</b> <i>filespec</i> <b>| Where-Object { !(Select-String</b> <i>pattern</i> <b>$_ -Quiet) }</b>
    <b>ls -r</b> <i>filespec</i> <b>| ? { !(sls</b> <i>pattern</i> <b>$_ -q) }</b>
    
  6. 列出所有不包含模式的文件名:

  7. <b>(Get-ChildItem -Recurse</b> <i>filespec</i> <b>| Where-Object { !(Select-String</b> <i>pattern</i> <b>$_ -Quiet) }).FullName</b>
    <b>(ls -r</b> <i>filespec</i> <b>| ? { !(sls</b> <i>pattern</i> <b>$_ -q) }).FullName</b>
    

1
此外,如果您只是在寻找包含任何地方的模式的文件,则可以使用 Select-String-List 参数,在找到第一个实例后放弃搜索。 - KyleMit
2
我希望提问者能稍微变化一下问题,这样就可以成为AA了。#1非常有用,Michael Sorens显然会PS! - cBlaine

38
这是我会做的方式,你不需要使用get-content。
ls -r | Select-String dummy | select line,path

或者

ls -r | Select-String dummy | fl *

查看不同的属性是什么...
这个更快。第二个参数是-filter:
ls -r . *.bat | select-string netsh

ls -r -path . -filter *.bat | select-string netsh

奇怪的是,我发现选择字符串模式也可以匹配目录名称。

3
+1,这对我的情况非常适用,但是使用 select Pattern, LineNumber, Filename 可以得到更简洁的输出。Line 返回包含您的模式字符串的整行内容。如果您希望,您也可以轻松将此输出到csv文件中。 - Protonova
3
这应该是最佳答案。在我的情况下,速度快了4-5倍。当你需要在许多文件上重复执行命令600次时,这会带来很大的差异。 - sfarbota
1
选择 Path,LineNumber 和 Line 更加简明。模式是多余的,因为你已经知道它是什么。 - 9 Guy

25

这将显示匹配模式的路径、文件名以及找到的内容行。

Get-ChildItem -Path d:\applications\*config -recurse |  Select-String -Pattern "dummy" 

1
如果能在结果之间添加一行就好了 :) - cladelpino

18

将您的内容管道化

Get-ChildItem -recurse | Get-Content | Select-String -pattern "dummy"

转换为fl *

您会发现路径已经作为对象的属性返回。

如果您只需要路径,请使用select pathselect -unique path来去除重复项:

Get-ChildItem -recurse | Get-Content | Select-String -pattern "dummy" | select -unique path

1
谢谢你们两个,这正是我要找的。不幸的是,当路径中涉及许多子目录时,PS会截断绝对路径并在行末添加三个点,例如\dir1\dir2\dir3\path...因此我不知道返回哪个文件。 有没有办法告诉PS在字符上少贪心一些,并麻烦显示完整路径?:) 非常感谢! - Bluz
3
你需要在 Get-ChildItem 命令后面加上 -File 开关,否则你会不断收到错误级联的信息,因为它试图在目录上调用 Get-Content 命令。 - RubberDuck
1
如果您需要完整路径,可以执行此操作(Get-ChildItem -recurse | Get-Content | Select-String -pattern "dummy").FullName。人们似乎忘记了PowerShell是面向对象的;当有疑问时,请查找属性。 - Kellen Stuart

12

我修改了上面的一个答案,以便为我提供更多信息。这让我省去了后来的第二个查询。大致是这样的:

Get-ChildItem `
        -Path "C:\data\path" -Filter "Example*.dat" -recurse | `
    Select-String -pattern "dummy" | `
    Select-Object -Property Path,LineNumber,Line | `
    Export-CSV "C:\ResultFile.csv"

我可以使用这个结构来指定路径和文件通配符,并将文件名、行号和相关行保存到输出文件中。


1
太棒了!感谢您提供这个额外的解决方案 :) 不过,您能否链接到您的解决方案所基于的答案,并命名该答案的作者以给予他们荣誉?谢谢! - Max Vollmer

9
Get-ChildItem -r | ? {$_.psiscontainer -eq $false} | ? {gc $_.pspath |select-string -pattern "dummy"}

这将为您提供所有文件的完整细节。

完全不知道 -r 也可以工作。以为你必须总是使用 -Recurse - Kellen Stuart

8

使用PowerShell,转到您的文件路径,然后键入此命令并替换 ENTER THE STRING YOU SEARCH HERE (但保留双引号):

findstr /S /I /M /C:"ENTER THE STRING YOU SEARCH HERE" *.*

祝您今天过得愉快


6
为了在结果数组中保留完整的文件细节,您可以对vikas368发布的答案进行轻微修改(该答案似乎与ISE自动完成不兼容)。请参考以下代码:
Get-ChildItem -Recurse | Where-Object { $_ | Select-String -Pattern "dummy" }

简而言之:
ls -r | ?{ $_ | Select-String -Pattern "dummy" }

5

如果您要搜索一个文件夹,可以这样做:

select-string -Path "c:\temp\*.*" -Pattern "result"  -List | select Path

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