在Powershell中选择CSV列,其中标题名称包含特定字符串

时间:2017-07-26 13:36:39

标签: powershell csv

我有一个大约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格式)?

4 个答案:

答案 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-MemberNoteProperty

$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属性并将它们作为列表行连接,最后每行都附加到文本文件中。 这可能不是教学上正确的方法来实现结果,但它到目前为止工作。 感谢大家的投入!