我正忙着尝试理解为什么此脚本无法按预期运行。这是一个简单的脚本,我尝试在其中导入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
}
答案 0 :(得分:4)
除非您将输入文件预先完整地读入内存 ,否则您将无法安全地从给定管道中读取和写回同一文件。 >
具体来说,诸如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
不产生任何输出。 / p>
为了安全起见,我将Import-Csv
的参数从$_
更改为$_.FullName
,以确保Import-Csv
找到输入文件(遗憾的是,文件-info对象$_
绑定为字符串,有时 会扩展为纯文件名)。
一个更安全的解决方案是先输出到临时文件,然后(仅)在成功完成后替换原始文件。
无论采用哪种方法,替换文件都将具有默认文件属性和权限;如果原始文件具有要保留的特殊属性和/或权限,则必须显式重新创建它们。
答案 1 :(得分:1)
正如马特(Matt)所评论的那样,您的最后一个$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
}
或者保留您的代码,添加包含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
}
答案 2 :(得分:0)
所以我知道了。我试图直接通过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
}