在 PowerShell 中进一步指定 Select -unique
Further Specifying Select -unique in PowerShell
我正在使用 PowerShell 重新格式化大型数据库。原始数据由设备标签名称和数据点组成。原始文件重复每个数据点的标签。此外,还有许多具有相同数据点的相似(不相同)标签。这是原始示例:
40028 "ALBENI F1" "1 " 0.00 -14.00 12.10
40028 "ALBENI F1" "1 " 2.70 -13.90 11.80
40028 "ALBENI F1" "1 " 4.50 -13.80 11.60
40028 "ALBENI F1" "1 " 7.30 -13.60 11.10
40028 "ALBENI F1" "1 " 10.00 -12.70 10.40
40028 "ALBENI F1" "1 " 12.30 -11.80 9.70
40028 "ALBENI F1" "1 " 12.70 -11.30 9.50
40028 "ALBENI F1" "1 " 14.50 -9.40 8.70
40028 "ALBENI F1" "1 " 16.30 -7.40 7.80
40028 "ALBENI F1" "1 " 16.80 -6.80 6.90
40028 "ALBENI F1" "1 " 17.20 -5.50 5.30
40028 "ALBENI F1" "1 " 17.80 -3.50 3.50
40028 "ALBENI F1" "1 " 18.20 0.00 0.00
40030 "ALBENI F2" "2 " 0.00 -14.00 12.10
在 Powershell 中,我设法让它看起来像这样:
40028 "ALBENI F1 " "1 " "YES"
, 0.00, -14.00, 12.10,
, 2.70, -13.90, 11.80,
, 4.50, -13.80, 11.60,
, 7.30, -13.60, 11.10,
, 10.00, -12.70, 10.40,
, 12.30, -11.80, 9.70,
, 12.70, -11.30, 9.50,
, 14.50, -9.40, 8.70,
, 16.30, -7.40, 7.80,
, 16.80, -6.80, 6.90,
, 17.20, -5.50, 5.30,
, 17.80, -3.50, 3.50,
, 18.20, 0.00, 0.00,
40063 "CGS " "1 " "YES"
, 0.00, -620.00, 680.00,
这就是我想要的格式。如您所见,我将所有标签都变成了单个 headers,并去掉了 ALBENI F2,因为它是 F1 的重复。我的问题是,为了到达那里,我使用了 select-object -unique
。根据需要,这消除了所有重复的 headers 和重复数据集。然而,它也删除了其他完全不同的标签上的重复数据点。这是无法接受的;因此,我需要一种方法来摆脱重复的标签和数据集,同时将所有数据点保留在唯一标签上,即使这些数据点与其他标签中的数据点相同。
如果有帮助,这是我的代码:
Get-Content (inputfile)|select -skip 2| select-string '}' -NotMatch |
%{$_ -replace '"\s+(\-?\d+\.\d+)\s+(\-?\d+\.\d+)\s+(\-?\d+\.\d+)','"" ,, , , ,'}|
%{$_ -split '"\s+,'} |
select -unique |
%{$_ -replace '"\s+("\w+")', ' " "YES"'}|
%{$_ -replace '"\s+("\w+\s+")', ' " "YES"'} |(outputfile)
里面有很多东西,而且一切正常。我只需要另一种整理重复项的方法。想法?
我将在这里采用不同的方法,将您的数据转换为 objects,然后您可以更轻松地过滤:
$data = Get-Content $inputfile -Raw # PowerShell 3+
#$data = (Get-Content $inputfile) -join '\n' # Use this with PowerShell 2
$obj = $data -replace ' {2,}', ' ' | ConvertFrom-Csv -Delimiter ' '
现在你有一个 collection 的 objects 属性,你可以根据需要进行过滤,例如:
$obj | Where-Object { $_.40028 -eq 40028 }
为了更好的可读性,您可能希望通过管道传输到 Format-Table
以查看其实际工作原理。
从你的问题中有点不清楚你最终想从中得到什么,所以很难证明更具体的查询。如果您对每一列都有 headers,这也会有所帮助,因为它会产生更有意义的 属性 名称。
说明
$data -replace ' {2,}', ' ' | ConvertFrom-Csv -Delimeter ' '
这会将 2 个或更多 space 的所有实例折叠成一个 space,这将有助于转换为 CSV。
我们告诉 ConvertFrom-Csv
我们正在使用单个 space 作为分隔符,然后它就发挥了它的魔力。它理解引用的字段,所以这在这里很有效。
如果您有 headers,您可以使用 -Header
指定它们,以便生成的属性具有良好的名称。
好的,所以我采取了完全不同的方法;我首先将文件拆分为 headers 和数据。然后,我用 get-unique 过滤了 headers,只留下数据。然后我将数据分成几组并在每个位置插入适当的 headers。这摆脱了所有额外的 headers,并将整个文件放入我需要的格式。我的全部代码如下。
[cmdletbinding()]
Param(
[Parameter(mandatory=$true,position=1)]
[string]$InputFilePath,
[Parameter(mandatory=$true,position=2)]
[string]$OutputFilePath
)
Get-Content $InputFilePath |select -skip 2| select-string '}' -NotMatch|%{$_ -replace '"\s+(\-?\d+\.\d+)\s+(\-?\d+\.\d+)\s+(\-?\d+\.\d+)','"" ,, , , ,'}| %{$_ -split '"\s+,'} |%{$_ -replace '"\s+("\w+")', ' " "YES"'}| %{$_ -replace '"\s+("\w+\s+")', ' " "YES"'}|out-file $OutputFilePath
$data=Get-Content $OutputFilePath| select-string ','
$data=$data|%{$_ -replace '(,\s+0.00,\s+\-?\d+\.\d+\,\s+\d+\.\d+)',':'}| %{$_ -split ':'}
$headers=Get-Content $OutputFilePath| select-string '"' | Get-Unique
$counter=0
$data | %{if($_.length -eq 0){$_ -replace '', ($headers|Select-Object -index $counter) ;$counter=$counter+1 }else{$_} }|out-file $OutputFilePath
这是我的完整代码,但这个问题的重要部分是我开始分配变量的地方。感谢大家的帮助!
我正在使用 PowerShell 重新格式化大型数据库。原始数据由设备标签名称和数据点组成。原始文件重复每个数据点的标签。此外,还有许多具有相同数据点的相似(不相同)标签。这是原始示例:
40028 "ALBENI F1" "1 " 0.00 -14.00 12.10
40028 "ALBENI F1" "1 " 2.70 -13.90 11.80
40028 "ALBENI F1" "1 " 4.50 -13.80 11.60
40028 "ALBENI F1" "1 " 7.30 -13.60 11.10
40028 "ALBENI F1" "1 " 10.00 -12.70 10.40
40028 "ALBENI F1" "1 " 12.30 -11.80 9.70
40028 "ALBENI F1" "1 " 12.70 -11.30 9.50
40028 "ALBENI F1" "1 " 14.50 -9.40 8.70
40028 "ALBENI F1" "1 " 16.30 -7.40 7.80
40028 "ALBENI F1" "1 " 16.80 -6.80 6.90
40028 "ALBENI F1" "1 " 17.20 -5.50 5.30
40028 "ALBENI F1" "1 " 17.80 -3.50 3.50
40028 "ALBENI F1" "1 " 18.20 0.00 0.00
40030 "ALBENI F2" "2 " 0.00 -14.00 12.10
在 Powershell 中,我设法让它看起来像这样:
40028 "ALBENI F1 " "1 " "YES"
, 0.00, -14.00, 12.10,
, 2.70, -13.90, 11.80,
, 4.50, -13.80, 11.60,
, 7.30, -13.60, 11.10,
, 10.00, -12.70, 10.40,
, 12.30, -11.80, 9.70,
, 12.70, -11.30, 9.50,
, 14.50, -9.40, 8.70,
, 16.30, -7.40, 7.80,
, 16.80, -6.80, 6.90,
, 17.20, -5.50, 5.30,
, 17.80, -3.50, 3.50,
, 18.20, 0.00, 0.00,
40063 "CGS " "1 " "YES"
, 0.00, -620.00, 680.00,
这就是我想要的格式。如您所见,我将所有标签都变成了单个 headers,并去掉了 ALBENI F2,因为它是 F1 的重复。我的问题是,为了到达那里,我使用了 select-object -unique
。根据需要,这消除了所有重复的 headers 和重复数据集。然而,它也删除了其他完全不同的标签上的重复数据点。这是无法接受的;因此,我需要一种方法来摆脱重复的标签和数据集,同时将所有数据点保留在唯一标签上,即使这些数据点与其他标签中的数据点相同。
如果有帮助,这是我的代码:
Get-Content (inputfile)|select -skip 2| select-string '}' -NotMatch |
%{$_ -replace '"\s+(\-?\d+\.\d+)\s+(\-?\d+\.\d+)\s+(\-?\d+\.\d+)','"" ,, , , ,'}|
%{$_ -split '"\s+,'} |
select -unique |
%{$_ -replace '"\s+("\w+")', ' " "YES"'}|
%{$_ -replace '"\s+("\w+\s+")', ' " "YES"'} |(outputfile)
里面有很多东西,而且一切正常。我只需要另一种整理重复项的方法。想法?
我将在这里采用不同的方法,将您的数据转换为 objects,然后您可以更轻松地过滤:
$data = Get-Content $inputfile -Raw # PowerShell 3+
#$data = (Get-Content $inputfile) -join '\n' # Use this with PowerShell 2
$obj = $data -replace ' {2,}', ' ' | ConvertFrom-Csv -Delimiter ' '
现在你有一个 collection 的 objects 属性,你可以根据需要进行过滤,例如:
$obj | Where-Object { $_.40028 -eq 40028 }
为了更好的可读性,您可能希望通过管道传输到 Format-Table
以查看其实际工作原理。
从你的问题中有点不清楚你最终想从中得到什么,所以很难证明更具体的查询。如果您对每一列都有 headers,这也会有所帮助,因为它会产生更有意义的 属性 名称。
说明
$data -replace ' {2,}', ' ' | ConvertFrom-Csv -Delimeter ' '
这会将 2 个或更多 space 的所有实例折叠成一个 space,这将有助于转换为 CSV。
我们告诉 ConvertFrom-Csv
我们正在使用单个 space 作为分隔符,然后它就发挥了它的魔力。它理解引用的字段,所以这在这里很有效。
如果您有 headers,您可以使用 -Header
指定它们,以便生成的属性具有良好的名称。
好的,所以我采取了完全不同的方法;我首先将文件拆分为 headers 和数据。然后,我用 get-unique 过滤了 headers,只留下数据。然后我将数据分成几组并在每个位置插入适当的 headers。这摆脱了所有额外的 headers,并将整个文件放入我需要的格式。我的全部代码如下。
[cmdletbinding()]
Param(
[Parameter(mandatory=$true,position=1)]
[string]$InputFilePath,
[Parameter(mandatory=$true,position=2)]
[string]$OutputFilePath
)
Get-Content $InputFilePath |select -skip 2| select-string '}' -NotMatch|%{$_ -replace '"\s+(\-?\d+\.\d+)\s+(\-?\d+\.\d+)\s+(\-?\d+\.\d+)','"" ,, , , ,'}| %{$_ -split '"\s+,'} |%{$_ -replace '"\s+("\w+")', ' " "YES"'}| %{$_ -replace '"\s+("\w+\s+")', ' " "YES"'}|out-file $OutputFilePath
$data=Get-Content $OutputFilePath| select-string ','
$data=$data|%{$_ -replace '(,\s+0.00,\s+\-?\d+\.\d+\,\s+\d+\.\d+)',':'}| %{$_ -split ':'}
$headers=Get-Content $OutputFilePath| select-string '"' | Get-Unique
$counter=0
$data | %{if($_.length -eq 0){$_ -replace '', ($headers|Select-Object -index $counter) ;$counter=$counter+1 }else{$_} }|out-file $OutputFilePath
这是我的完整代码,但这个问题的重要部分是我开始分配变量的地方。感谢大家的帮助!