2013/03/16

PowerShellのforループで2変数を初期化するにはどうすれば良いのかと、昨日とある方に質問されました。C#やJavaScriptなんかでは

for (int i = 0, j = 10; i < 10; i++, j--){}

のように初期化子を,で区切って複数指定できますが、PowerShellでは

for ($i = 0, $j = 10; $i -lt 10; $i++, $j--){}

という書き方ができません。初期化子部分には一つの変数しか書けないのです。

そこで考えたのが部分式を利用する方法です。部分式は一つの式に複数の文を埋め込むための書式で、

Write-Host "今日は $($d = Get-Date; $d.ToString("M/dd")) です。"

こんな感じで$()の中に複数の文を入れて変数のように実行結果の値を参照できます。なお、部分式の内部は、スクリプトブロックとは違い、外側と同じスコープとなります。

この部分式をforループの初期化子に利用してみます。

for ($($i = 0; $j = 3); $i -lt 3; $i++, $j--)
{
    "$i $j"
}

実行結果は

0 3
1 2
2 1

となりちゃんと動いてますね。

この書き方が果たして正式なものなのか、分かりませんが、forループで複数値の初期化をしたいときに使えるテクなんじゃないでしょうか。

ちなみにPowerShellのforループの初期化子宣言はループ内のスコープにおける変数とはならず、ループの外側でも参照や代入ができてしまいますので注意です。forループの中は別スコープとはならないのですね。それは部分式を使っても同じです。(それだったらforループの前で変数初期化しても同じことじゃん、となるかもしれませんが…)

また例をみていただければ分かりますが、反復式の部分は,で複数指定できるようです。ただしこの,はforステートメントの構文の一部ではなく、配列連結演算子の,だと思います。

追記。エントリ読み返して気づいたんですが、反復式を配列として記述できるのだから、初期化も配列でやっちゃえば良かったですね。このように。

for ($i, $j = 0, 3; $i -lt 3; $i++, $j--)
{
    "$i $j"
}

こっちのほうがいいですね。

2008/02/22

VBScript から Windows PowerShell へ
http://www.microsoft.com/japan/technet/scriptcenter/topics/winpsh/convert/dim.mspx

によると、

$a = [string]

でできるとあるんですがこれは嘘ですね。

PS C:\Users\daisuke> $a = [string]
PS C:\Users\daisuke> $a

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     String                                   System.Object


PS C:\Users\daisuke> $a -is [string]
False
PS C:\Users\daisuke> $a.gettype().fullname
System.RuntimeType

RCとかの段階ではそうだったのかもしれませんが…

New-Variableコマンドレットを使っても初期値を-valueパラメータで与えないと駄目です。

結論として「PowerShellには(値を初期化しない)変数宣言をする方法はない」となると思います。

追記。

と思ったらできました。

New-Variable -name x

これで$xという$nullの変数ができます。型は指定できないみたいですが。

元記事:http://blogs.wankuma.com/mutaguchi/archive/2008/02/22/124522.aspx

2006/12/28

PowerShellの配列は基本的に値の入った固定長の配列が作成できます。

たとえば

$a=1,2,3,4,5
$b=6..10
[system.diagnostics.process[]]$proc=get-process

等々。でも空の固定長の配列も実は作成可能であるという話をこの前ある方から聞きました。

PS C:\> [Int32[]]$ar = new-object System.Int32[] 5
PS C:\> $ar.IsFixedSize
True
PS C:\> $ar.Length
5
PS C:\> $ar
0
0
0
0
0

こんな感じです。5が気持ち悪い方は(5)でもいいです。要はnew-objectコマンドレットでSystem.Int32[]の配列を作り、コンストラクタに配列のサイズを指定しているのですね。0で初期化されてしまうのはどうにかならないかな。まあめったに使うことはないと思いますが一応ここでも取り上げておきます。

元記事:http://blogs.wankuma.com/mutaguchi/archive/2006/12/28/53984.aspx


Copyright © 2005-2018 Daisuke Mutaguchi All rights reserved
mailto: mutaguchi at roy.hi-ho.ne.jp
プライバシーポリシー

Twitter

Books