【问题标题】:Recursively search a directory for files whose content matches a regex and collect the paths of matching files in an array递归搜索目录中内容与正则表达式匹配的文件,并在数组中收集匹配文件的路径
【发布时间】:2017-06-15 21:44:35
【问题描述】:
$locations = Get-ChildItem $readLoc -recurse | ? {!$_.psiscontainer} | select-object name | %{$e = $_.name; get-content $e}

$array = @()

for($i = 0; $i -lt $locations.length; $i++){
    #if($locations.name[$i].length -eq "9"){
        $paths = Resolve-Path $locations.fullname[$i]
        $paths.path
        get-content $locations.name[$i]
        #$array += $paths.path 
    #}
}

我需要遍历文件系统中的每个文件并打开每个文件。我正在检查文件中的字符串是否与正则表达式匹配,然后将该文件的完整路径输出到数组中。

但是,$locations 不接受获取内容。

获取内容:找不到路径

'C:\Users\xxxxxx\Documents\files\powershell\OWASP_ApplicationThreatModeling.docx'
because it does not exist.
At line:1 char:89
+ ... .psiscontainer} | select-object name |%{$e = $_.name; get-content $e}
+                                                           ~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\Users\p61782...atModeling.docx:String) [Get-Content], ItemNotFoundEx
   ception
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetContentCommand.

【问题讨论】:

  • 删除|Select-Object Name | %{$e = $_.name; get-content $e},然后在下面将其更改为get-content $locations[$i].fullname。或者更好的是,将您的Get-ChildItem 传递给Select-String,因为它默认使用正则表达式进行匹配。

标签: powershell powershell-4.0


【解决方案1】:

正如TheMadTechnician 建议的那样,使用Select-String 执行正则表达式匹配会更有效:

$locations = Get-ChildItem $readLoc -File -Recurse |
               Select-String -List -Pattern '^\d{3}-?\d{2}-?\d{4}$' | 
                 Select-Object -ExpandProperty Path

注意:
- 传递给-Pattern 的正则表达式是linked to in a comment 的简化版本。
请注意正则表达式如何包含在 '...' 而不是 "..." 中,以防止 PowerShell 对字符串的无意预先解释。

  • Get-ChildItem $readLoc -File -recurse 递归枚举目标目录子树中的所有文件。 PSv3+ 中提供了开关-File(以及对应的-Directory),使您的? {!$_.psiscontainer} 过滤器变得不必要。

  • Select-String 可以对通过Get-ChildItem 管道传输的文件的内容 进行操作,并默认执行正则表达式匹配:

    • -List 告诉 Select-String 仅返回每个输入文件中的 first 匹配项(如果有)。
  • Select-String 返回匹配信息对象,其.Path 属性包含输入文件的完整路径,因此Select-Object -ExpandProperty Path 仅用于输出任何文件的路径包含至少 1 个匹配项。

总体而言,变量 $locations 因此接收到那些文件的完整路径的数组,其中至少有 1 行与感兴趣的正则表达式匹配。
请注意,如果输出包含超过 1 个元素,PowerShell 会自动从 array 中的命令收集输出。


至于你尝试了什么:

  • 您的直接问题是您将.Name - 即一个文件名称 - 传递给Get-Content 而不是.FullName

  • 此外,您的明显意图是在数组 $locations 中收集 file-info 对象,而您的管道实际上生成了 所有文件的内容(如行数组)。

【讨论】:

  • yayyy...刚刚得知我现在必须将其与 .docx、.pdf、.xls 以及可能的其他一些文件格式一起使用...有什么线索吗?
  • @schnipdip:您应该问一个 new 问题,但简短的回答是,除非可以将这些文件原始读取为纯文本文件,否则可能会产生错误肯定的 - 您需要了解这些文件格式的专用 cmdlet,并且可以直接搜索它们或提取它们的纯文本内容以在 PowerShell 中进行匹配。
  • 是的,我就是这么想的。那里有可以读取多种文件格式的阅读器。因此,如果我能得到一个 API,我认为它会好起来的。如果不使用 3rd 方应用程序,我什至不知道从哪里开始从 powershell 读取其他文件格式。
【解决方案2】:

您需要使用 FullName 属性。现在,您正在使用 Select-Object 命令剥离它。

$locations = Get-ChildItem $readLoc -recurse | ? {!$_.psiscontainer}

for($i = 0; $i -lt $locations.length; $i++){
    $locations[$i].fullname
    get-content $locations[$i].fullname
}

【讨论】:

  • 我可以让它工作,但是当我使用for($i = 0; $i -lt $locations.length; $i++){ $locations[$i].fullname $content = get-content $locations[$i].fullname if($content -match "^(\d{3}-\d{2}-\d{4})|(\d{3}\d{2}\d{4})|(\d{3}\s{1}\d{2}\s{1}\d{4})$"){ $array += $locations[$i].fullname $array 并尝试将它附加到数组时它什么也没做。最重要的是,它不会将任何东西放入数组中。测试文件中有匹配的正则表达式。
  • 我在原始帖子的更新部分添加了我的代码版本
猜你喜欢
  • 1970-01-01
  • 2017-01-10
  • 2016-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多