PowerShell逐行读取文本文件并在文件夹中查找丢失的文件

时间:2017-11-07 21:40:12

标签: powershell

我是一个寻求帮助的新手。我有一个包含两列数据的文本文件。一列是供应商,一列是发票。 我需要逐行扫描该文本文件,并查看路径中供应商和发票是否匹配。在路径$ Location中,第一个通配符是供应商编号,第二个通配符是Invoice 我希望非匹配输出到文本文件。

$Location = "I:\\Vendors\*\Invoices\*"
$txt = "C:\\Users\sbagford.RECOEQUIP\Desktop\AP.txt"
$Output ="I:\\Vendors\Missing\Missing.txt"
foreach ($line in Get-Content $txt) {
if (-not($line -match $location)){$line}
}
set-content $Output -value $Line

来自txt或csv文件的示例数据。

kvendnum    wapinvoice
000953  90269211
000953  90238674
001072  11012016
002317  448668
002419  06123711
002419  06137343
002419  06134382
002419  759208
002419  753087
002419  753069
002419  762614
003138  N6009348
003138  N6009552
003138  N6009569
003138  N6009612
003182  770016
003182  768995
003182  06133429

在上面的数据中,唯一的匹配是在第二行:000953 90238674 和第6行:002419 06137343

1 个答案:

答案 0 :(得分:0)

未经测试,但这是我接近它的方式:

$Location = "I:\\Vendors\\.+\\Invoices\\.+"
$txt = "C:\\Users\sbagford.RECOEQUIP\Desktop\AP.txt"
$Output ="I:\\Vendors\Missing\Missing.txt"
select-string -path $txt -pattern $Location -notMatch |
    set-content $Output

没有必要逐行浏览文件; PowerShell可以使用select-string为您执行此操作。 -notMatch参数只是反转搜索并通过任何与模式不匹配的行发送。

select-string发送一个matchinfo个对象流,其中包含符合搜索条件的行。这些对象实际上包含的信息只有匹配行,但幸运的是,PowerShell非常聪明,知道如何将相关项目发送到set-content

正则表达式可能很难做到正确,但如果您要执行此类任务,则值得深入了解。

修改

$Location  = "I:\Vendors\{0}\Invoices\{1}.pdf"
$txt = "C:\\Users\sbagford.RECOEQUIP\Desktop\AP.txt"
$Output  = "I:\Vendors\Missing\Missing.txt"

get-content -path $txt | 
    % {

        # extract fields from the line
        $lineItems = $_ -split "  "

        # construct path based on fields from the line
        $testPath = $Location -f $lineItems[0], $lineItems[1]

        # for debugging purposes
        write-host ( "Line:'{0}'  Path:'{1}'" -f $_, $testPath )

        # test for existence of the path; ignore errors
        if ( -not ( get-item -path $testPath -ErrorAction SilentlyContinue ) ) {
            # path does not exist, so write the line to pipeline
            write-output $_ 

        }

    } |
    Set-Content -Path $Output

我想我们必须逐行挑选文件。如果有一种更惯用的方法可以做到这一点,那就让我望而却步。

上面的代码假定输入文件中的格式一致,并使用-split将行拆分为数组。

编辑 - 第3版

$Location  = "I:\Vendors\{0}\Invoices\{1}.pdf"
$txt = "C:\\Users\sbagford.RECOEQUIP\Desktop\AP.txt"
$Output  = "I:\Vendors\Missing\Missing.txt"

get-content -path $txt | 
    select-string "(\S+)\s+(\S+)" | 
    %{

        # pull vendor and invoice numbers from matchinfo     
        $vendor = $_.matches[0].groups[1]
        $invoice = $_.matches[0].groups[2]

        # construct path
        $testPath = $Location -f $vendor, $invoice

        # for debugging purposes
        write-host ( "Line:'{0}'  Path:'{1}'" -f $_.line, $testPath )

        # test for existence of the path; ignore errors
        if ( -not ( get-item -path $testPath -ErrorAction SilentlyContinue ) ) {
            # path does not exist, so write the line to pipeline
            write-output $_ 
        }

    } |
    Set-Content -Path $Output

-split " "似乎在运行的脚本中表现得与它在命令行上的行为方式不同。奇怪的。无论如何,这个版本使用正则表达式来解析输入行。我根据原始帖子中的示例数据对其进行了测试,似乎有效。

正则表达式分解如下

(     Start the first matching group
\S+   Greedily match one or more non-white-space characters
)     End the first matching group
\s+   Greedily match one or more white-space characters
(     Start the second matching group
\S+   Greedily match one or more non-white-space characters
)     End the second matching groups