2

我正在努力理解为什么这个脚本没有按预期工作。这是一个简单的脚本,我尝试在其中导入 CSV,选择我想要的几列,然后导出 CSV 并复制自身。(基本上我们已经归档了数据,由于内存大小限制,我只需要来自另一个项目的几列)。这个脚本非常简单,显然它与它不起作用时引起的挫败程度成反比......现在最终结果是我最终得到一个空的 csv 而不是只包含我选择的列的 csv与选择对象。

$RootPath = "D:\SomeFolder"

$csvFilePaths = Get-ChildItem $RootPath -Recurse -Include *.csv | 
    ForEach-Object{
        Import-CSV $_ |
        Select-Object Test_Name, Test_DataName, Device_Model, Device_FW, Data_Avg_ms, Data_StdDev | 
        Export-Csv $_.FullName -NoType -Force
}
4

3 回答 3

5

除非您预先将输入文件完全读入内存,否则您无法安全地读取和写回给定管道中的同一文件。

具体来说,诸如Import-Csv file.csv | ... | Export-Csv file.csv擦除.file.csv

最简单的解决方案是将读取输入文件的命令包含在 中(...),但请注意:

  • 文件的内容(转换为对象)必须作为一个整体适合内存

  • 如果在所有(转换的)对象都写回文件之前中断管道,则存在轻微的数据丢失风险。

应用于您的命令:

$RootPath = "D:\SomeFolder"

Get-ChildItem $RootPath -Recurse -Include *.csv -OutVariable csvFiles | 
    ForEach-Object{
        (Import-CSV $_.FullName) | # NOTE THE (...)
          Select-Object Test_Name, Test_DataName, Device_Model, Device_FW, 
                        Data_Avg_ms, Data_StdDev | 
            Export-Csv $_.FullName -NoType -Force
}

请注意,我使用-OutVariable csvFiles它来收集输出变量中的 CSV 文件信息对象$csvFiles。您尝试收集文件路径的$csvFilePaths = ...尝试不起作用,因为它尝试收集Export-Csv输出,但Export-Csv不产生任何输出。

另外,为了安全起见,我将Import-Csv参数从更改$_$_.FullName以确保Import-Csv找到输入文件(因为遗憾的是, file-info 对象$_被绑定为string有时会扩展为仅仅是 file name)。


安全的解决方案是先输出到临时文件,并且(仅)在成功完成后替换原始文件。

无论采用哪种方法,替换文件都将具有默认文件属性和权限;如果原始文件具有您想要保留的特殊属性和/或权限,您必须明确地重新创建它们。

于 2018-07-11T00:45:17.147 回答
1

正如马特评论的那样,您的最后一个$PSItem ($_)不再与 相关,Get-ChildItem而是与Select-Object没有FullName属性的 cmdlet 相关

您可以使用不同的 foreach 方法:

$RootPath = "D:\SomeFolder"
$csvFilePaths = Get-ChildItem $RootPath -Recurse -Include *.csv

foreach ($csv in $csvFilePaths)
{
Import-CSV $csv.FullName |
Select-Object Test_Name,Test_DataName,Device_Model,Device_FW,Data_Avg_ms,Data_StdDev | 
Export-Csv $csv.FullName -NoType -Force
}

或者保留您的代码,添加$CsvPath包含 csv 路径的变量并稍后使用它:

$RootPath = "D:\SomeFolder"
Get-ChildItem $RootPath -Recurse -Include *.csv | ForEach-Object{
$CsvPath = $_.FullName
Import-CSV $CsvPath |
Select-Object Test_Name,Test_DataName,Device_Model,Device_FW,Data_Avg_ms,Data_StdDev | 
Export-Csv $CsvPath -NoType -Force
}
于 2018-07-10T19:12:54.060 回答
0

所以我想通了。我试图直接通过 Import-Csv cmdlet 进行管道传输,而不是在 og 代码中将其声明为变量。这是我想要完成的代码片段,完成了。我之前试图直接在 Import-Csv cmdlet 中进行管道传输,我只需要声明一个使用 Import-Csv cmdlet 作为其定义的变量,然后将该变量通过管道传递给 Select-Object,然后是 Export-Csv cmdlet。谢谢大家的帮助,不胜感激!

$RootPath = "\someDirectory\"
$CsvFilePaths = @(Get-ChildItem $RootPath -Recurse -Include *.csv)
$ColumnsWanted = @('Test_Name','Test_DataName','Device_Model','Device_FW','Data_Avg_ms','Data_StdDev')
for($i=0;$i -lt $CsvFilePaths.Length; $i++){
  $csvPath = $CsvFilePaths[$i]
  Write-Host $csvPath
  $importedCsv = Import-CSV $csvPath 
  $importedCsv | Select-Object $ColumnsWanted | Export-CSV $csvPath -NoTypeInformation
}
于 2018-07-11T17:44:42.787 回答