次のようなファイルがあります:
a、1
b、2
c、3
a、4
b、5
c、6
(...数千行を繰り返す)
どうすればこれに置き換えることができますか?
a、b、c
1,2,3
4,5,6
ありがとう
次のようなファイルがあります:
a、1
b、2
c、3
a、4
b、5
c、6
(...数千行を繰り返す)
どうすればこれに置き換えることができますか?
a、b、c
1,2,3
4,5,6
ありがとう
これが地獄からのブルートフォースワンライナーです:
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スクリプトブロックの両方で最後のカーリーの後にバックティックを付ける必要があります。このスクリプトは、新しい-split演算子に依存しているため、PowerShell2.0が必要です。
このアプローチでは、Foreach-Objectコマンドレットを多用します。通常、パイプラインでForeach-Object(別名Foreach)を使用する場合は、次のように1つのスクリプトブロックのみを指定します。
Get-Process | Foreach {$_.HandleCount}
これにより、各プロセスのハンドル数が出力されます。このForeach-Objectの使用法では、-Processスクリプトブロックを暗黙的に使用します。これは、パイプラインから受け取るオブジェクトごとに1回実行されることを意味します。では、各プロセスのすべてのハンドルを合計したい場合はどうでしょうか。これを行うために使用できるという事実を無視して、Measure-Object HandleCount -Sum
Foreach-Objectがこれを行う方法を示します。この問題の元の解決策に見られるように、Foreachは、パイプラインの最初のオブジェクトに対して1回実行されるBeginスクリプトブロックと、パイプラインにオブジェクトがなくなったときに実行されるEndスクリプトブロックの両方を取得できます。Foreach-Objectを使用してハンドル数を合計する方法は次のとおりです。
gps | Foreach -Begin {$sum=0} -Process {$sum += $_.HandleCount } -End {$sum}
これを問題の解決策に関連付けると、Beginスクリプトブロックでいくつかの変数を初期化して、名前と値の配列と、ヘッダーが出力されたかどうかを示すブール値($ hdr)を保持します(出力するだけです)。一度)。次のやや気が遠くなるようなことは、$namesと$valuesに格納されている現在のデータセットを出力するために、ProcessスクリプトブロックとEndスクリプトブロックの両方から呼び出すBeginスクリプトブロックで関数(出力)も宣言することです。
他の唯一のトリックは、Processスクリプトブロックが-contains演算子を使用して、現在の行のフィールド名が以前に表示されているかどうかを確認することです。その場合は、現在の名前と値を出力し、それらの配列を空にリセットします。それ以外の場合は、名前と値を適切な配列に格納して、後で保存できるようにします。
ところで、出力関数がグローバルを使用する必要がある理由:変数の指定子は、ネストされたスコープがスコープ外で定義された変数を変更するときに、PowerShellが「コピーオンライト」アプローチを実行するためです。ただし、実際にその変更をより高いスコープで実行する場合は、global:やscript:などの修飾子を使用してPowerShellに通知する必要があります。