我有一个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
}
3条答案
按热度按时间yqyhoc1h1#
*除非您将输入文件读取到内存中 * 完全,预先 ,否则无法安全地读取和写回给定管道中的同一文件。
具体地说,像
Import-Csv file.csv | ... | Export-Csv file.csv
这样的命令将 * 擦除 *file.csv
的内容。最简单的解决方案是**将读取输入文件的命令括在
(...)
**中,但请注意:*文件的内容(转换为对象)必须适合整个内存。
应用于您的命令:
注意,我使用
-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
的内容dtcbnfnu2#
正如Matt所评论的,您的最后一个
$PSItem ($_)
不再与Get-ChildItem
相关,而是与不具有FullName
属性的Select-Object
cmdlet相关您可以使用不同的foreach方法:
或者保留您的代码,添加包含csv路径的
$CsvPath
变量,稍后使用它:mgdq6dx13#
所以我想明白了。我试图直接通过管道导入Import-Csv cmdlet,而不是将其声明为o.g.中的变量。代码。这里是代码片段,它得到了我想做的事情。我之前尝试直接通过管道导入Import-Csv cmdlet,我只需声明一个使用Import-Csv cmdlet作为其定义的变量,并通过管道将该变量导入Select-Object,然后导入Export-Csv cmdlet。谢谢大家的帮助,我很感激!