我有一个大约10-15列的数据文件,我想从中提取特定的列。一些列我知道确切的列标题和其他我只知道前两个字母将始终是“FC”。 如何仅选择我知道列标题的列和以“FC”开头的列? 从“FC”列开始,我尝试过这样:
$myCSV = Import-CSV "mydata.txt" -Delimiter "`t"
$FCcols = $myCSV[0].psobject.Properties | foreach { $_.Name } | Where {$_ -match "FC"}
$myCSV | select $FCcols
但我得到一个错误:
Select-Object : Cannot convert System.Management.Automation.PSObject to one of
the following types {System.String, System.Management.Automation.ScriptBlock}.
At line:3 char:16
+ $myCSV | select <<<< $FCcols
+ CategoryInfo : InvalidArgument: (:) [Select-Object], NotSupport
edException
+ FullyQualifiedErrorId : DictionaryKeyUnknownType,Microsoft.PowerShell.Co
mmands.SelectObjectCommand
然后,如果我尝试:
$myCSV = Import-CSV "mydata.txt" -Delimiter "`t"
$FCcols = [System.Collections.ArrayList]@()
$myCSV[0].psobject.Properties | foreach { $_.Name } | Where {$_ -match "FC"} | %{$FCcols.Add($_)}
$myCSV | select $FCcols
我得到了我想要的输出,除了它是“列标题:值”格式,如下所示:
FC1839 : 0
FC1842 : 1
FC1843 : 6
FC1844 : 12
FC1845 : 4
FC1839 : 0
FC1842 : 0
FC1843 : 19
FC1844 : 22
FC1845 : 14
我可能只是遗漏了一些简单的东西,但是我如何能够选择这些匹配的列,然后将它们输出到另一个.txt文件(没有header:value格式)?
答案 0 :(得分:3)
首先要做的事情:Mathias R. Jessen's有用的提示不仅可以解决您的问题,还可以显着简化方法(也适用于PSv2):
$myCSV | Select-Object FC*
(隐含的)-Property
参数支持通配符表达式,因此FC*
匹配以FC
开头的所有属性(列名称)。
至于输出格式您会看到:因为您选择了5个属性,所以PowerShell默认采用隐式Format-List
格式,每个属性名称 - 值对在它自己的路线上。
要修复此显示问题,请明确地将管道Format-Table
(如果您选择了4个或更少的属性,PowerShell会隐式执行此操作):< / p>
$myCSV | Select-Object FC* | Format-Table
要将结果重新导出为CSV(TSV)文件:
Import-Csv mydata.txt -Delimiter "`t" | Select-Object FC* |
Export-Csv myresults.txt -Encoding Utf8 -Delimiter "`t" -NoTypeInformation
为此没有标题行:
Import-Csv mydata.txt -Delimiter "`t" | Select-Object FC* |
ConvertTo-Csv -Delimiter "`t" -NoTypeInformation | Select-Object -Skip 1 |
Set-Content myresults.txt -Encoding Utf8
至于您的特定症状:
问题只出现在PSv2 中,它闻起来像个臭虫。
解决方法使您的列名数组成为强类型字符串数组([string[]]
):
[string[]] $FCcols = $myCSV[0].psobject.Properties | % { $_.Name } | ? { $_ -match '^FC' }
请注意,为简洁起见,我使用内置别名%
代替ForEach-Object
和?
代替Where-Object
。
另请注意,传递给-match
的正则表达式已更改为^FC
,以确保只匹配以<{1}}开始的列。
您的代码在PSv3 +中按原样运行,但可以简化:
FC
请注意$FCcols = $myCSV[0].psobject.Properties.Name -match "^FC"
如何直接应用于.Name
,在v3 +中会导致在集合的每个项目上调用.psobject.Properties
成员,这是一项功能叫member enumeration。
答案 1 :(得分:1)
我会使用Get-Member
来获取您的列,如下所示:
$myCSV = Import-CSV "mydata.txt" -Delimiter "`t"
$myCSV | select ($myCSV | gm -MemberType NoteProperty | ? {$_.Name -match 'FC'}).Name
答案 2 :(得分:0)
Mathias的有用评论是选择的最佳方式;简单而优雅 - 不知道这是一种选择。
$myCSV | Select *FC*,ColumnIKnowTheNameOf
我相信你需要添加Export-Csv
来回答你的上一个问题。如果您将来需要查询csv /类似对象,我已经采用的另一种方法是使用Get-Member
和NoteProperty
。
$myCSV = Import-CSV "mydata.txt" -Delimiter "`t"
# you can get the headings by using Get-Member and Selecting NoteProperty members.
$FCcols = $myCSV |
Get-Member |
Where-Object {$_.MemberType -eq "NoteProperty" -and $_.Name -match "FC"} |
Select-Object -ExpandProperty Name
# you add names to this array.
$FCcols += "ColumnIKnowTheNameOf"
$myCSV | Select-Object $FCcols
# to get a tab-delimited file similar to the one you imported, use Export-Csv
$myCSV | Export-csv "myresults.txt" -Delimiter "`t" -NoTypeInformation
答案 3 :(得分:0)
我终于想出了一个快速而又肮脏的#34;我很失望的解决方案,以前没有弄清楚。
$myCSV = Import-CSV "mydata.txt" -Delimiter "`t" | select FC*
for ($i = 0; $i -lt $myCSV.count; $i++){
$writeline = ($myCSV[$i] | %{$_.PSObject.Properties | %{$_.Value}}) -join "`t"
ac "myresults.txt" $writeline -Encoding utf8}
第一行给出了我想要的列,然后for循环获取每列的value属性并将它们作为列表行连接,最后每行都附加到文本文件中。 这可能不是教学上正确的方法来实现结果,但它到目前为止工作。 感谢大家的投入!