如何使用PowerShell递归搜索目录和子目录中的所有文件?

时间:2021-02-22 20:03:45

标签: linux powershell recursion .net-core tree

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

tree 函数中,文件(或文件名及其路径)如何传递给此处的 SearchString 函数?

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

会话记录:

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”匹配。目标是使用上述 Calibre 搜索整个 PowerShell 库。


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

    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”文件时触发。缺少这个逻辑。但更大的缺失是如何从 SearchFile 函数调用 tree 以便搜索每个文件。

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

2 个答案:

答案 0 :(得分:3)

你真的把事情复杂化了。您可以通过使用 Get-ChildItem 在 $dir 路径中递归查找您的 txt 文件,然后将这些 FileInfo 对象直接通过管道传递给 Select-String 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)'

答案 1 :(得分:2)

当您指定 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 参数。

相关问题