我不明白递归发生在哪里,也不明白它在下面的 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
以便搜索每个文件。
这是怎么做到的?撇开文件类型或文件扩展名不谈。没有看到递归发生的地方。
答案 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
参数。