我在一个文件夹中有数百个文本文件,这些文件通常可以相互引用,并深入到服务器级别。不确定我是否能很好地解释这一点,所以我将举一个例子来解释。
假设文件夹"A"包含500.txt文件。第一个可能被称为A.txt,在那里的某个地方它提到了B.txt,然后又提到了C.txt等等。我相信下降的级别不超过10个。
现在,我想通过程序化地遍历该文件来找到与a.txt相关的某些文本字符串,然后如果它看到对其他.txt文件的引用也会遍历它们,以此类推。得到的输出将类似于a_out.txt,它包含了它基于正则表达式找到的所有内容。
我一开始使用Powershell,但现在有点卡住了:
$files = Get-ChildItem "C:TEST" -Filter *.txt
$regex = ‘PCB.*;’
for ($i=0; $i -lt $files.Count; $i++) {
$infile = $files[$i].FullName
$outfile = $files[$i].BaseName + "_out.txt"
select-string $infile -Pattern $regex -AllMatches | % { $_.Matches } | % { $_.Value } > $outfile
}
它遍历每个.txt文件并输出与PCB匹配的所有内容。*;表达式转换为相应的_out.txt文件。
我完全不知道现在如何扩展它以包括对其他文件的引用。我甚至不确定这在PowerShell中是否可行,或者我是否需要使用另一种语言来实现我想要的目标。
我可以让一些办公室猴子手动完成这一切,但如果这相对简单,那么它将为我们节省大量时间。如有任何帮助,我们将不胜感激:)
/编辑
当我在脑海中思考这个问题时,我想每次提到另一个文件时,我都可以建立一个数组,然后对这些文件重复这个过程。然而,回到我最初的问题,我不知道我会怎么做。
/编辑2:
对不起,我已经离开几天了,我只是刚刚接这个。我一直在利用我从这个问题和其他一些问题中学到的知识来提出以下问题:
function Get-FileReference
{
Param($FileName, $OutputFileName='')
if ($OutputFileName -eq '')
{
Get-FileReference $FileName ($FileName -replace '.xml$', '_out.xml')
}
else
{
Select-String $FileName -Pattern 'BusinessObject.[^"rns][w.]*' -AllMatches | % { $_.Matches } | % { $_.Value } | Add-Content $OutputFileName
Set-Location C:TEST
$References = (Select-String -Pattern '(?<=resid=")d+' -AllMatches -path $FileName | % { $_.Matches } | % { $_.Value })
Write "SC References: $References" | Out-File OUTPUT.txt -Append
foreach ($Ref in $References)
{
$count
Write "$count" | Out-File OUTPUT.txt -Append
$count++
Write "SC Reference: $Ref" | Out-File OUTPUT.txt -Append
$xml = [xml](Get-Content 'C:TESTpackage.xml')
$res = $xml.SelectSingleNode('//res[@id = $Ref]/child::resver[last()]')
$resource = $res.id + ".xml"
Write "File to Check $resource" | Out-File OUTPUT.txt -Append
Get-FileReference $resource $OutputFileName
}
}
}
$files = gci "C:TEST" *.xml
ForEach ($file in $files) {
Get-FileReference $file.FullName
}
在我最初的问题之后,我意识到这比我最初想象的要广泛一点,因此必须进行修补。
以下是值得注意的要点:
- 所有父文件都是.xml和上匹配的代码"BusinessObject"等按预期工作
- 对其他文件不是简单的.txt,而是需要的模式匹配'(?<=resid=")d+'
- 此模式匹配需要与另一个文件package.xml交叉引用,并基于值它返回,接下来需要查找的文件是[newname].xml
- 和以前一样,这些子.xml文件可以引用其他.xml文件
我在上面粘贴的代码似乎陷入了无尽的循环中(因此我现在在那里进行调试),它不喜欢在中使用$Ref
$res = $xml.SelectSingleNode('//res[@id = $Ref]/child::resver[last()]')
这会导致以下错误:
Exception calling "SelectSingleNode" with "1" argument(s): "Namespace Manager or XsltContext needed. This query has a prefix, variable, or user-defined function."
由于可能有数百个文件,当它超过1000+时就会死亡。
一个递归函数,它尝试执行您想要的操作。
function Get-FileReference
{
Param($FileName, $OutputFileName='')
if ($OutputFileName -eq '')
{
Get-FileReference $FileName ($FileName -replace '.txt$', '_out.txt')
}
else
{
Select-String -Pattern 'PCB.*;' -Path $FileName -AllMatches | Add-Content $OutputFileName
$References = (Select-String -Pattern '^.*.txt' -AllMatches -path $FileName).Matches.Value
foreach ($Ref in $References)
{
Get-FileReference $Ref $OutputFileName
}
}
}
$files = gci *.txt
ForEach ($file in $files) { Get-FileReference $file.FullName }
它需要两个参数——一个文件名和一个输出文件名。如果在没有输出文件名的情况下调用,它会假设它位于新递归树的顶部,并生成一个要附加到的输出文件名。
如果使用输出文件名调用(即自己调用),它会搜索PCB模式,附加到输出,然后在任何文件引用上调用自己,使用相同的输出文件名。
假设文件引用本身是不带空格的行xyz.txt
。