この連載では、PowerShellについて学んでいきます。前回の記事はこちらになります。
前回は配列(System.Arrayクラス)の静的メソッドについて学びました。

今回も配列です。配列の複製について見ていきます。簡単そうにみえるのですが、ちょっと奥が深いのです。
変数の値コピー
変数の値をコピーするには「=」演算子で変数同士を結べばよいです。
PS > $a = 1 PS > $b = $a PS > $a , $b 1 1 PS > $a = 2 PS > $a , $b 2 1
コピー後にコピー元の変数を確認しても、コピー先の変数の値は変わりません。何故このような確認をしてみたかというと、配列では少し動作が異なるからです。
配列の場合
配列で同様の操作をして、挙動を見てみましょう。
PS > $a = @(1) PS > $b = $a PS > $a , $b 1 1 PS > $a[0] = 2 PS > $a , $b 2 2
コピー元の配列要素を変更すると、コピー先の配列も変更されます。これは、配列の場合「=」演算子で結ぶと参照先がコピーされるからです。
配列要素の値コピー
それでは配列要素の値をコピーする場合は、どうすればいいのでしょうか。この場合は、以下にご紹介するメソッドを使用します。
Cloneメソッド
Cloneメソッドを使用すると、配列要素の値をコピーできます。
PS > $a = @(1) PS > $b = $a.Clone() PS > $a , $b 1 1 PS > $a[0] = 2 PS > $a , $b 2 1
元の配列を変更してもコピー先の値はそのままです。
CopyToメソッド
CopyToメソッドを使用しても、配列要素の値をコピーできます。記述方法は以下の通りです。
コピー元配列.CopyTo(コピー先配列, コピー先開始位置)
コピー先の配列はあらかじめ用意する必要があります。また、コピーする開始位置を指定できます。
PS > $a = @(1 , 2) PS > $b = @(0 , 0 , 0 , 0) PS > $a.CopyTo($b , 1) PS > $b 0 1 2 0
[Array]::Copy()
前回ご紹介した静的メソッドである「[Array]::Copy()」でもコピー可能です。詳細は前回を参照してください。
3つのメソッドは、以下のように使い分けます。
- 全体の配列を丸ごと新しい配列に複製したい場合: Clone
- 既存の配列に元の配列の内容をコピーして、特定の位置から上書きしたい場合: CopyTo
- 部分的に、または異なる開始位置やコピーする要素数を指定してコピーしたい場合: 静的な [Array]::Copy
シャローコピーとディープコピー
これらのメソッドで行われるコピーはシャローコピー(浅いコピー)といいます。要素が配列の場合は参照先がコピーされるだけで、値はコピーされません。以下の例を見てみましょう。
PS > $a = @(@(1) , @(2) , @(3)) PS > $b = $a.Clone() PS > $b 1 2 3 PS > $b[0][0] 1 PS > $b[0][0] = 2 PS > $a 2 2 3
コピーした変数の配列要素の値を変更すると、コピー元の配列要素も同様に変更されています。
参照先ではなく値を直接コピーする方法をディープコピー(深いコピー)といいます。 PowerShellにはディープコピーをするメソッド、コマンドレットがありません。ディープコピーするには、各要素を個別にコピーするしかありません(シリアライズ/デシリアライズを使用した方法があるようですが、難解なようですので割愛します)。
PS > $a = @(@(1) , @(2) , @(3)) PS > $b = @(0 , 0 , 0) PS > $b[0] = $a[0] PS > $b[1] = $a[1] PS > $b[2] = $a[2] PS > $b 1 2 3 PS > $b[0] = 5 PS > $b 5 2 3 PS > $a 1 2 3
配列の要素に配列を指定する方法は、避けたほうがいいみたいです。
二次元配列
二次元配列を作成するには、コマンドレット「New-Object」を使用します。New-Objectは、オブジェクトのインスタンスを作成します。以下は2×3の二次元配列の例です。
PS > $a = New-Object 'Int[,]' 2,3 PS > $a[0,0] = 1 PS > $a[0,1] = 2 PS > $a[0,2] = 3 PS > $a[1,0] = 4 PS > $a[1,1] = 5 PS > $a[1,2] = 6 PS > $a.GetType() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True Int32[,] System.Array PS > $a 1 2 3 4 5 6
こちらも「=」演算子で結ぶと参照先がコピーされます。値のコピーはシャローコピーで行います。
PS > $b = $a PS > $b[0,0] 1 PS > $a[0,0] = 2 PS > $b[0,0] 2 PS > $a[0,0] = 1 PS > $b = $a.Clone() PS > $b[0,0] 1 PS > $a[0,0] = 2 PS > $b[0,0] 1
次回はパイプライン
いかがでしょうか。配列を扱う場合には、参照先のコピー、値のコピーの違いに注意したいですね。次回は関数です。今までは1行でひとつのコマンドを実行して、結果を出力していました。関数を使用すると複数のコマンドをまとめて実行、結果を取得したり、値を渡して実行できたりします。お楽しみに!!