我有一个看起来像这样的文件:
一,1个
B,2
C,3
一个,4
B,5
C,6
(...重复1000行)
如何将其转换为此?
A,B,C
1,2,3
4,5,6
由于
答案 0 :(得分:7)
这是一个来自地狱的蛮力单线:
PS> Get-Content foo.txt |
Foreach -Begin {$names=@();$values=@();$hdr=$false;$OFS=',';
function output { if (!$hdr) {"$names"; $global:hdr=$true}
"$values";
$global:names=@();$global:values=@()}}
-Process {$n,$v = $_ -split ',';
if ($names -contains $n) {output};
$names+=$n; $values+=$v }
-End {output}
a,b,c
1,2,3
4,5,6
这不是我所说的优雅,但应该让你过去。这应该按原样正确复制/粘贴。但是,如果您将其重新格式化为上面显示的内容,则需要在Begin和Process脚本块的最后一个卷曲之后放回。此脚本需要PowerShell 2.0,因为它依赖于新的-split运算符。
此方法大量使用Foreach-Object cmdlet。通常,当您在管道中使用Foreach-Object(别名为Foreach)时,您只需指定一个脚本块:
Get-Process | Foreach {$_.HandleCount}
打印出每个进程的句柄计数。 Foreach-Object的这种用法隐式使用-Process scriptblock,这意味着它对从管道接收的每个对象执行一次。现在如果我们想要为每个进程总计所有句柄呢?忽略你可以使用Measure-Object HandleCount -Sum
来执行此操作的事实,我将向您展示Foreach-Object如何执行此操作。正如您在此问题的原始解决方案中所看到的,Foreach可以同时获取为管道中的第一个对象执行一次的Begin脚本块和在管道中不再有对象时执行的End脚本块。以下是使用Foreach-Object总计句柄数的方法:
gps | Foreach -Begin {$sum=0} -Process {$sum += $_.HandleCount } -End {$sum}
将此问题与问题解决方案联系起来,在Begin scriptblock中我初始化一些变量以保存名称和值的数组以及bool($ hdr),它告诉我标题是否已输出(我们只想输出一次)。下一个有点令人兴奋的事情是我还在Begin脚本块中声明了一个函数(输出),我从Process和End脚本块调用它来输出存储在$ names和$ values中的当前数据集。
唯一的另一个技巧是Process scriptblock使用-contains运算符来查看之前是否已经看到当前行的字段名称。如果是,则输出当前名称和值,并将这些数组重置为空。否则只需将名称和值存储在适当的数组中,以便以后保存。
BTW输出函数需要在变量上使用global:说明符的原因是当嵌套作用域修改在其作用域之外定义的变量时,PowerShell执行“写时复制”方法。但是,当我们真的希望在更高的范围内进行修改时,我们必须告诉PowerShell使用像global:或script这样的修饰符:。