PS脚本正在导出空CSV

g9icjywg  于 2023-05-11  发布在  其他
关注(0)|答案(3)|浏览(131)

我有一个helluva的时间试图理解为什么这个脚本没有按预期工作。这是一个简单的脚本,我试图导入CSV,选择我想要的几列,然后导出CSV并复制它本身。(基本上,由于内存大小的限制,我们已经存档了一些数据,我只需要从另一个项目中提取几列数据)。这个脚本非常简单,这显然与当它不起作用时它所引起的挫折感成反比。现在的最终结果是我最终得到一个空的csv,而不是一个只包含我用Select-Object选择的列的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
}
yqyhoc1h

yqyhoc1h1#

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

具体地说,像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来收集输出变量$csvFiles中的CSV文件信息对象。您尝试通过$csvFilePaths = ...收集文件路径是不起作用的,因为它尝试收集 * Export-Csv的 * 输出,但Export-Csv没有产生任何输出。
此外,为了安全起见,我将Import-Csv参数从$_更改为$_.FullName,以确保Import-Csv找到输入文件(因为,遗憾的是,文件信息对象$_被绑定为 string,* 有时 * 扩展为 * 单纯的文件名 *)。
一个更安全的解决方案先输出到一个临时文件,并且(仅)在成功完成后替换原始文件。
无论使用哪种方法,替换文件都将具有默认的文件属性和权限;如果原始文件具有您想要保留的特殊属性和/或权限,则必须显式地重新创建它们。
[1]请注意,在其他情况下(在Windows上),您可能只是得到一个 * 错误 *,不会导致输入文件的内容被删除;例如以下管线:Get-Content file.txt | ForEach-Object { "[$_]" } | Set-Content file.txt报告错误The process cannot access the file '...\file.txt' because it is being used by another process,但不擦除file.txt的内容

dtcbnfnu

dtcbnfnu2#

正如Matt所评论的,您的最后一个$PSItem ($_)不再与Get-ChildItem相关,而是与不具有FullName属性的Select-Object 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
}

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

$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
}
mgdq6dx1

mgdq6dx13#

所以我想明白了。我试图直接通过管道导入Import-Csv cmdlet,而不是将其声明为o.g.中的变量。代码。这里是代码片段,它得到了我想做的事情。我之前尝试直接通过管道导入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
}

相关问题