使用引用

时间:2016-07-19 00:29:24

标签: file loops powershell search

我在一个文件夹中有数百个文本文件,这些文件通常可以互相引用,并且可以深入到几个级别。我不确定我是否正在解释这个问题,所以我将以一个例子来解释。

假设文件夹“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:\TEST\package.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
} 

按照我原来的问题,我意识到这比我原先想象的要广泛得多,因此不得不修补。

这些是值得注意的要点:

  1. 所有父文件都是.xml和匹配的代码     “BusinessObject”等按预期工作。
  2. 对其他人的引用     文件不仅仅是.txt,而是需要模式匹配     '(?&lt; = resid =“)d +'
  3. 此模式匹配需要与另一个文件 package.xml 交叉引用并基于该值     它返回,它接下来需要查看的文件是 [newname] .xml
  4. 和以前一样,那些子.xml文件可以引用一些.xml文件     其他.xml文件
  5. 我上面粘贴的代码似乎陷入无限循环(因此我现在在那里进行调试)并且它不喜欢使用 $ 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 +时会死掉。

1 个答案:

答案 0 :(得分:1)

一个递归函数,试图做你想要的。

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