似乎While循环不会产生可以在管道中继续的输出。我需要处理一个大(很多GiB)文件。在这个简单的例子中,我想提取第二个字段,对其进行排序,然后只获取唯一值。什么我不了解While循环并通过管道推送东西?
在* NIX世界中,这将很简单:
cut -d "," -f 2 rf.txt | sort | uniq
在PowerShell中,这不会那么简单。
源数据。
PS C:\src\powershell> Get-Content .\rf.txt
these,1,there
lines,3,paragraphs
are,2,were
剧本。
PS C:\src\powershell> Get-Content .\rf.ps1
$sr = New-Object System.IO.StreamReader("$(Get-Location)\rf.txt")
while ($line = $sr.ReadLine()) {
Write-Verbose $line
$v = $line.split(',')[1]
Write-Output $v
} | sort
$sr.Close()
输出。
PS C:\src\powershell> .\rf.ps1
At C:\src\powershell\rf.ps1:7 char:3
+ } | sort
+ ~
An empty pipe element is not allowed.
+ CategoryInfo : ParserError: (:) [], ParseException
+ FullyQualifiedErrorId : EmptyPipeElement
答案 0 :(得分:2)
使它变得比它需要的复杂一点。您有一个没有标题的CSV。以下应该有效:
Import-Csv .\rf.txt -Header f1,f2,f3 | Select-Object -ExpandProperty f2 -Unique | Sort-Object
答案 1 :(得分:2)
纳西尔的解决方法看起来就像去了这里。
如果您想知道代码中出现了什么问题,答案是 (实际上这是真的,我将保留其中的示例,但向下滚动以了解它的真正原因#39;为你工作)。while
循环(和do
/ while
/ until
循环)不要像PowerShell中的其他语句那样始终将值返回到管道
ForEach-Object
- 一个cmdlet,不是内置语言功能/声明;确实将对象返回到管道。
1..3 | % { $_ }
foreach
- 陈述;确实会回来。
foreach ($i in 1..3) { $i }
if
/ else
- 声明;确实会回来。
if ($true) { 1..3 }
for
- 陈述;确实会回来。
for ( $i = 0 ; $i -le 3 ; $i++ ) { $i }
switch
- 陈述;确实会回来。
switch (2)
{
1 { 'one' }
2 { 'two' }
3 { 'three' }
}
但由于某些原因,这些其他循环似乎无法预测。
永远循环,返回$i
(0
;不进行递增)。
$i = 0; while ($i -le 3) { $i }
什么都不返回,但$i
确实增加了:
$i = 0; while ($i -le 3) { $i++ }
如果将表达式包装在括号中,它似乎会返回:
$i = 0; while ($i -le 3) { ($i++) }
但事实证明(我在这里学习了一点),while
奇怪的回归语义与你的错误无关;您无法将语句管道转换为函数/ cmdlet,无论它们的返回值如何。
foreach ($i in 1..3) { $i } | measure
会给你同样的错误。
你可以绕过"这可以通过使整个语句成为$()
:
$( foreach ($i in 1..3) { $i } ) | measure
在这种情况下,这对你有用。或者在您的while
循环中,而不是使用Write-Output
,您只需将项目添加到数组中,然后对其进行排序:
$arr = @()
while ($line = $sr.ReadLine()) {
Write-Verbose $line
$v = $line.split(',')[1]
$arr += $v
}
$arr | sort
我知道你在这里处理一个大文件,所以也许你会想到通过逐行管道sort
,你将避免大量的内存占用。在许多情况下,管道在PowerShell中以这种方式工作,但关于排序的事情是你需要整个集合来对它进行排序,因此Sort-Object
cmdlet将是"收集"无论如何你转移到它的每个项目,然后最后进行实际的排序;我不确定你能完全避免这种情况。诚然,让Sort-Object
这样做而不是自己构建阵列可能会更有效,这取决于它的实现方式,但我不认为你会在RAM上节省很多。
答案 2 :(得分:0)
其他解决方案
Get-Content -Path C:\temp\rf.txt | select @{Name="Mycolumn";Expression={($_ -split "," )[1]}} | select Mycolumn -Unique | sort