【问题标题】:How to recursively search all files in a directory and sub-directories using PowerShell?如何使用 PowerShell 递归搜索目录和子目录中的所有文件?
【发布时间】:2021-05-25 02:30:57
【问题描述】:

我不明白递归发生在哪里,也不知道它是如何在下面的 tree 函数中使用的(这是为了模拟一些 linux tree 命令结果)。

tree 函数,如何将文件(或文件名及其路径)传递给这里的SearchString 函数?

对于上下文,这是一个 REPL 会话,演示了单个文件的最终目标:获取文件的 PSPath 属性,并将该属性用于简单的 regex

会话记录:

posh> $dir = "/home/nicholas/Calibre Library/Microsoft Office User/549 (1476)"
posh> $files = Get-ChildItem -Path $dir –File
posh> $files.Length
3
posh> $files[0].Extension
.txt
posh> $files[0].PSPath
Microsoft.PowerShell.Core\FileSystem::/home/nicholas/Calibre Library/Microsoft Office User/549 (1476)/549 - Microsoft Office User.txt
posh> $pattern = '(?=.*?foo)(?=.*?bar)'
posh> $string = Get-Content $files[0]
posh> $string | Select-String $pattern

此文件没有任何“foo”和“bar”匹配项。目标是使用上述PowerShell 搜索整个Calibre 库。


Calibre 库的 tree 的大量输出被修剪为单个结果:

    Directory: /home/nicholas/Calibre Library/Microsoft Office User/548 (1474)

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-----           2/20/2021  3:22 AM         159883 548 - Microsoft Office User.txt
-----           2/20/2021  2:13 AM         351719 cover.jpg
-----           2/20/2021  2:39 AM           1126 metadata.opf

posh> ./worker.ps1

上面的文件和路径是如何传递给SearchString函数的?

目标是遍历整个库并搜索所有纯文本文件。 (假设纯文本文件具有“.txt”扩展名。)

库代码:

function SearchFile($dir,$file)
{
    $path =  [string]::Concat($dir,"/",$file)
    $pattern='(?=.*?foo)(?=.*?bar)'
    $string = Get-Content $path
    $result = $string | Select-String $pattern
    $result
}


function tree($dir)
{
    "$dir"
    $tree = Get-ChildItem -Recurse
    $tree = Get-ChildItem -Path $dir -Recurse
    # get any files and invoke SearchFile here ?
    $tree
}

工人代码:

. /home/nicholas/powershell/functions/library.ps1


$dir = "/home/nicholas/Calibre Library"

tree $dir

SearchFile 函数的执行应在找到“.txt”文件时触发。缺少那个逻辑。但更大的缺失部分是如何从tree 函数调用SearchFile,以便搜索每个文件。

这是怎么做到的?撇开文件类型或文件扩展名不谈。没有看到递归发生的位置。

【问题讨论】:

    标签: linux powershell recursion .net-core tree


    【解决方案1】:

    Get-ChildItem 已经在您指定 -Recurse 参数时为您执行递归。对于您的代码,它没有任何区别。您可以使用 ForEach-Object 以与未指定 -Recurse 相同的方式处理所有文件信息的线性列表。

    SearchFile 函数应在找到“.txt”文件时执行。

    使用-Filter 参数指定*.txt。此外,当您只想获取文件时,请始终传递-File。这允许文件系统提供程序已经跳过目录,这样更快也更正确(理论上可能存在名为foo.txt 的目录,这会让SearchFile 出错)。

    function tree($dir)
    {
        "$dir"
        Get-ChildItem -Path $dir -Recurse -File -Filter *.txt | ForEach-Object {
            SearchFile -dir $_.Directory.PSPath -file $_.Name
        }        
    }
    

    我不知道为什么你的函数SearchFile 有单独的目录和文件名参数。 Get-ChildItem 已经在 $_.PSPath 中输出了完整路径。将路径分开并在SearchFile 中再次将其连接在一起没有多大意义。我建议您将它们替换为单个 Path 参数。

    【讨论】:

      【解决方案2】:

      你真的把事情复杂化了。您可以很容易地做到这一点,方法是使用 Get-ChildItem 在 $dir 路径中递归查找 txt 文件,然后将这些 FileInfo 对象直接传送到 Select-String cmdlet,该 cmdlet 接受管道输入并从传递给它的 FileInfo 对象中获取 PSPath并做它的事。 Select-String 将对 Get-ChildItem 发送给它的每个对象执行此操作,这些对象是在 $dir 路径中递归找到的所有 txt 文件的 FileInfo 对象。

      $dir = '/home/nicholas/Calibre Library/Microsoft Office User/549 (1476)'
      Get-ChildItem -Recurse -Path $dir -Filter *.txt |
          Select-String -Pattern '(?=.*?foo)(?=.*?bar)'
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-12-13
        • 1970-01-01
        • 2018-08-26
        • 2010-12-31
        • 1970-01-01
        • 2012-04-07
        • 1970-01-01
        相关资源
        最近更新 更多