Sesame Script

驚きのループ

Sesame Script

スクリプト作成初心者のためのコラム、"Sesame Script" へようこそ。このコラムの目的は、システム管理自動化に使用する Windows スクリプトの基礎を紹介することです。皆様がスクリプトを読んで理解し、ニーズに合わせてスクリプトを変更するために必要な情報を提供いたします。スクリプト作成について何かよくわからない点がありましたら、ご連絡ください (英語のみ)。多くの方が同じ疑問を抱えているはずです。

過去の記事については、Sesame Script アーカイブを参照してください。

*
トピック
驚きのループ驚きのループ
コレクションコレクション
配列配列
For ループFor ループ
特典情報特典情報
来月もアクセスしてください...来月もアクセスしてください...

驚きのループ

グランドチトン山の麓にあるログ キャビン (米国ワイオミング州にある悩める人々のための場所) で 1 週間を過ごした後、怠惰な 1 週間を送ったこの Scripting Guy は、慌しい都会生活に戻り、生活のために働いています。それが今月のコラムとどんな関係があるのでしょうか。たいした関係はないのですが、おそらくまだ頭がまともに働いていないので、ループをトピックとして取り上げることにしましょう。

ループは、スクリプトで頻繁に必要になるものです。その主な理由は、オブジェクトやプロパティの多くが、それらのコレクションとして返されるからです。したがって、まずコレクションについてお話してから、ループについて説明しましょう。そうそう、ループで頻繁に使用する、配列というものもあります。したがって、コレクション、配列、それからループの順に説明していきます。まあ、そんなところでしょう。

申し上げたとおり、まだ頭がまともに働いていません。ご辛抱ください (チトン山の熊とは何の関係もありません。私たちは熊を探しましたが、見つかりませんでした)。このコラムを筋の通ったものにできるかどうか今にわかるでしょうから。

ページのトップへページのトップへ

コレクション

オブジェクトやプロパティを理解したら、コレクションを理解するのは簡単です。オブジェクトやプロパティを理解していない場合は、「クラスはセッション中」を参照してください。

簡単に言えば (そして正確に言うと、結局のところ)、コレクションは文字どおり、コレクションです。人々が切手、ベースボール カード、フルーツをテーマにしたクッキー瓶のコレクションを持っているように、スクリプトには...、お待ちください。申し上げる前にちょっと考えてみてください。スクリプトではどんなコレクションを使用するでしょうか。その答えは、このコラムの一番下に上下逆向きに記載してあります。

しまった、この記事に上下逆向きのテキストを表示する方法がわからなかったので、申し上げます。スクリプトでは、オブジェクトやプロパティのコレクションを使用します。何のためにでしょうか。よくぞたずねてくださいました。

コレクションの例

特定のコンピュータ上にあるすべてのディスク ドライブの一覧を表示するとします。ローカル コンピュータ上でこの情報を検索するには、次のように FileSystemObject にアクセスします。

Set objFSO = CreateObject("Scripting.FileSystemObject")

このコードを使用すると、変数 objFSO 内に FileSystemObject のインスタンスを取得できます。ここで、ドライブを検索する必要があります。FileSystemObject というドライブにあるオブジェクト (オブジェクトが他のオブジェクトを含んでいる可能性があります) やプロパティを探すことになるので、次のようなスクリプトを実行します。

Set objDrive = objFSO.Drive

このドライブを探しても、見つからないでしょう。というのは、ほとんどのコンピュータには複数のドライブがあるからです。最近は、少なくともハード ドライブと CD ドライブがあります。1 つのドライブ オブジェクトを返すことになっていた場合、FileSystemObject は返すべきドライブをどのように認識するのでしょうか。 FileSystemObject は、1 つのドライブをランダムに推測して返すのではなく、ドライブのコレクションを返します。

Set colDrives = objFSO.Drives

colDrives 変数は、FileSystemObject オブジェクトがコンピュータ上で見つけたすべてのドライブを含んでいるコレクションです。

それでは、これらのドライブの種類を実際に確認するにはどうしたらいいでしょうか。次のスクリプトを実行しますか。

Wscript.Echo colDrives.DriveLetter

いいえ。ループを利用すれば、わずか 1 分で実行できることをお見せしましょう。ただし、まず配列について説明します。

実は、配列の説明に入る前に、コレクションについて指摘すべき点がいくつかあります。まず、ほとんどの場合、スクリプトの作成者はコレクションに何も割り当てません。この例で FileSystemObject によってドライブのコレクションが提供されているように、コレクションが返されます。

次に、コレクションが要素を 1 つしか含んでいない可能性があります。要素がゼロのコレクションが存在する可能性もあります。コンピュータ上にドライブがない場合 (その可能性は低いですが、私たちはあまりにも怠慢で、新しい例を思いつきません)、colDrives コレクションには何も含まれていません。

詳細

Collections – Microsoft Windows 2000 Scripting Guide (英語)

Collections with Zero Items – Microsoft Windows 2000 Scripting Guide (英語)

ページのトップへページのトップへ

配列

コレクション内の個々の項目にアクセスする方法について説明する前に、ループ処理が必要な別の種類のデータとして配列についてお話します。配列は、項目の集まりを保持するコレクションのようなものです。それでは、コレクションのコレクションと配列のコレクションにはどのような違いがあるのでしょうか。

コレクションには、クラスから取得された項目が含まれています。これらの項目には、プロパティやオブジェクトが含まれます (ただし、メソッドは含まれません。それではつじつまが合いません。メソッドは呼び出すもので、取得するものではありません)。実は、コレクションは複数の要素を含んでいる 1 種のオブジェクトです。したがって、前述の「コレクション」のセクションでご覧になったように、コレクションを変数に割り当てる場合は、一般に Set ステートメントを使用します。一方、配列には任意のデータ型に関する一連の要素が含まれています。オブジェクトが含まれていることもありますが、文字列、文字、数値などの VBScript で使用可能なデータ型が含まれている場合もあります。配列の変数には、Set ステートメントを使用しなくても、値を割り当てることができます。配列は、情報をまとめるためのコンテナにすぎません。

配列の例

実際の配列の例はまだお見せしませんが (ループを含んでいない例をお見せするのは難しいのです)、どのように動作するかを説明します。まず、配列に文字を割り当て、これらの文字をエコーします。

Dim arrArray(7)

arrArray(0) = "m"
arrArray(1) = "y"
arrArray(2) = " "
arrArray(3) = "a"
arrArray(4) = "r"
arrArray(5) = "r"
arrArray(6) = "a"
arrArray(7) = "y"

Wscript.Echo arrArray(0) & arrArray(1) & arrArray(2) & arrArray(3) & _
    arrArray(4) & arrArray(5) & arrArray(6) & arrArray(7)

ご覧のとおり、1 行目が Dim ステートメントで始まっています。そのことについては、記事「変数と定数」で説明しませんでしたが、この方法をお勧めします (それについてはいつか説明します)。とりあえず、Dim ステートメントに関して知っておくべきことは、スクリプト内のどこかで変数を使用することを VBScript プログラムに指定するということです。変数を使用するには、その前に Dim ステートメントを使用してその変数を宣言します。他の変数にもこのステートメントを実行する場合があり、ここではその理由を説明しませんが、配列の場合はこのステートメントは必須です (場合によります。それついては後述します)。Dim ステートメントを使用して、特定の変数 (この場合は arrArray) をスクリプト内で変数として使用することを VBScript に指定します。また、変数名の後にかっこを挿入することにより、この特定の変数が配列であることを VBScript に指定します。

Dim ステートメントが必須である理由は、通常、後にかっこが続くコードは、メソッドだからです。

DoSomethingNow(x)

配列に値を割り当てるとき、かっこ内の数値を使用して、どの位置の配列に値を格納するかを指定します。したがって、この場合は、文字 "m" を位置 0 (VBScript の配列は通常 0 から始まります) に格納すると指定しています。

arrArray(0) = "m"

しかし、それと同時に、arrArray は、呼び出そうとしているメソッドではなく、配列であることを VBScript スクリプトに指定する必要があります。そのため、配列に値を割り当てる前に、Dim ステートメントを使用して事前に VBScript に警告する必要があるのです。

Dim ステートメントについて知っておくべきことがもう 1 つあります。かっこ内にどのように数値を指定するかわかりましたか。これは、配列に入れる要素の数で、配列のサイズと呼ばれています。

サイズがわからない場合はどうなるのでしょうか。

この質問は、最後にしてください。まずこのスクリプトの説明を終えましょう。

したがって、7 つの要素を保持する配列が必要なことを VBScript に指定しました。いいえ、実際には、8 つの要素を保持する配列が必要なことを VBScript に指定したのです。

何ですか。8 つ? なぜ 8 つになるか?

質問は後にしてくださいとお願いしたはずです。後でご説明します。

配列内の各要素には位置があります。食料品店で卵を 1 パック買うときのように。卵はそれぞれパックの窪みに入っています。12 個の卵の場合は明らかに、各卵に 1 つずつ、12 個の窪みがパックに必要です。したがって、11 の配列としてパックを定義します。

いいえ、それは違いますね。12 と言いましたね。

いいですか。次にうっかり質問してしまった人は、私たちがこの問題を解決するまで隅に立ってもらいますよ。

VBScript では、配列の位置番号はゼロから始まります。したがって、窪みが 12 個ある場合、番号は 0 から 11 までとなります。Dim ステートメントを使用して配列を宣言する場合、配列に入る要素の数ではなく、その最大の番号を指定します。そのため、配列のサイズは通常、配列内の要素の数から 1 を引いた数として定義されます。

スクリプトの作成を開始した時点で、配列に要素がいくつ入るかわからない場合もあります。その場合は、Dim ステートメントを使用して配列を宣言する必要がありますが、かっこは空にします。

Dim arrArray()

必要な要素の数がわかった時点で、ReDim ステートメントを使用して配列を再び宣言します。

ReDim arrArray(5)

ループ処理に触れずに説明できるのは、こんなところです。ここで、質問をお受けしましょう (あそこの隅にいる方を除きます)。質問はありませんか。結構です。先に進みましょう。

詳細

Arrays – Microsoft Windows 2000 Scripting Guide (英語)

ReDim ステートメント – VBScript ランゲージ リファレンス

ページのトップへページのトップへ

For ループ

どんな要素をループするかがわかったところで、2 つのループ方法、For Each ループと For Next ループについて検討していきます。

For Each

For Each ループは次のようになります。

For Each <element> in <collection>
    ' do something
Next

ご覧のように、通常コレクションをこのような方法でループします。<collection> をコレクション変数の名前に置き換え、<element> に新しい変数名を入力します。ディスク ドライブの例に戻りましょう。これまでに作成したコードは次のとおりです。

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set colDrives = objFSO.Drives

コレクション変数は colDrives です。これはオブジェクトのコレクションなので、<element> objDrive を呼び出します。

For Each objDrive in colDrives
    ' do something
Next

簡単な日本語で言うと、"ドライブのコレクション内にあるドライブ オブジェクトごとに、特定のアクションを実行します" ということです。したがって、VBScript で For Each 行が初めて実行されるとき、コレクション内の最初のドライブが objDrive オブジェクト変数に挿入されます。それから、その後の行の実行に移ります。Next ステートメントは、ループの終わりを示し、その特定のドライブに対する必要な処理がすべて完了したことを示します。その特定のオブジェクトに対する処理が完了したので、コレクションの次のオブジェクトに進みます。その時点で、スクリプトは For Each ステートメントに戻り、コレクション内の次のオブジェクトが取得されて、 そのオブジェクトが objDrive に割り当てられます。このプロセスは、For Each ステートメントがコレクション内の次の項目を探して、見つからなくなるまで続行します。そうなった時点で、ループから抜け出し、Next ステートメントの次の行の実行に進みます。

次の例を試してみてください。

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set colDrives = objFSO.Drives

For Each objDrive in colDrives
    Wscript.Echo "Drive letter: " & objDrive.DriveLetter
Next

Wscript.Echo "Done"

For Next

ここで、似たようなループをご紹介します。For Next ループです。このループは、主にループを何回実行するかがわかっている場合に、配列で一般に使用します。For Next ループは次のようになります。

For <counter> = <start> to <end>   
     ' do something
Next

<counter> は、皆さんが入力する変数です (通常は、i などの 1 文字を使用します)。<start> 値でループのカウントを開始し、<end> でカウントを終了します。その例を次に示します。

For i = 0 to 3
    ' do something
Next

他の数値でも簡単に開始できます。

For i = 9 to 12
    ' do something
Next

ループを開始する値は、ループ内で行う処理と、任意の要素にカウンタ変数を使用するかどうかによって異なります。次の例をご覧になると、このタイプのループが配列に非常に役立つ理由がおわかりになるでしょう。

Dim arrCount()

size = 3
ReDim arrCount(size)

For i = 0 to size
    arrCount(i) = i
    Wscript.Echo arrCount(i)
Next

Wscript.Echo "Done "

この例からの出力は、次のようになります。

0
1
2
3
Done

For Next ステートメントの動作は、For Each ステートメントの場合とほとんど同じです。2 つのステートメントの違いは、ループを何回処理するかを指定することです。最初のループで開始値が変数 i に割り当てられます。この場合は、このループを初めて処理するので、i には値 0 が割り当てられます。その後、For ステートメントに続く行が実行され、Next ステートメントに達するまで続行されます。Next ステートメントに達したら、For ステートメントに戻ります。2 回目に For ステートメントに入った時点で、値 i は 1 だけ増えるので、この場合の 2 回目のループでは、i は 1 になります。For ステートメントでは、ループが処理されるたびに、値が 1 だけ増え、最後の数値に達するまでそれが繰り返されます。最後の数値に達したら (この場合は、サイズ値の 3)、For ステートメントに続く行が、最後に 1 回実行されます。その後、Next ステートメントから For ステートメントに戻りますが、この時点で、最後の値が渡されたので、For ループから抜け出し、Next ステートメントに続く行を実行します。

実際には、ループを処理するたびに 1 だけ増やす必要はありません。これが既定ですが、1 の代わりに任意の整数だけ増やすことができます。

Dim arrCount()

size = 3
ReDim arrCount(size)

For i = 0 to size Step 2
    arrCount(i) = i
    Wscript.Echo arrCount(i)
Next

Wscript.Echo "Done "

このスクリプトを実行すると、開始値 (0) を使用して最初のループが処理され、次のループで 2 だけ増えます。したがって、出力は次のようになります。

0
2
Done

逆方向にカウントすることもできます (開始値は、終了値よりも大きい数値を設定する必要があります。そうしないと、ループから抜け出してしまいます)。次の例を試してみてください。

Dim arrCount()

size = 3
ReDim arrCount(size)

For i = size to 0 Step -1
    arrCount(i) = i
    Wscript.Echo arrCount(i)
Next

Wscript.Echo "Done "

詳細

For Each – Microsoft Windows 2000 Scripting Guide (英語)

For Each…Next ステートメント – VBScript ランゲージ リファレンス

For Next – Microsoft Windows 2000 Scripting Guide (英語)

For…Next ステートメント – VBScript ランゲージ リファレンス

ページのトップへページのトップへ

特典情報

これは特典情報というほどのものではありませんが、"その他のさまざまなコレクション/配列/ループ要素" よりも聞こえがいいです。

配列で For Each を使用する

コレクションでは For Each ループを使用し、配列では For Next ループを使用すると述べました。ただし、配列で For Each ループを使用することもできます。

Dim arrArray(3)

arrArray(0) = 100
arrArray(1) = 150
arrArray(2) = 200
arrArray(3) = 250

For Each intArray in arrArray
    Wscript.Echo intArray
Next

このスクリプトの動作は、コレクションの場合とまったく同じです。最初のループで、配列 arrArray(0) の最初の要素が intArray に割り当てられ、その要素が出力されます。次のループで、配列 arrArray(1) の 2 番目の要素が intArray に割り当てられ、同様の処理が繰り返されます。

Dim を使用しないで配列を作成する

先ほど配列を宣言する Dim ステートメントの使用方法について説明したとき、場合によっては Dim ステートメントが必須であると述べました。配列に要素を挿入する方法は他にもあります。Array メソッドを使用できます。

arrArray = Array("m","y"," ","a","r","r","a","y")

Wscript.Echo arrArray(0) & arrArray(1) & arrArray(2) & arrArray(3) & _
    arrArray(4) & arrArray(5) & arrArray(6) & arrArray(7)

このスクリプトをメモ帳にコピーして実行してください (その方法がわからない場合は、「スクリプト : 最初のステップ」を参照してください)。エラー メッセージが表示されずに動作します。Dim ステートメントを使用する必要がない理由は、Array メソッドを実行すると、配列が返されるからです。VBScript では、配列が arrArray 変数に入力されたことを認識します。

ループから抜け出す

特定の値を求めてコレクションをループするとします。その値が見つかったら、ループを続行する必要はありません。時間の無駄です。ループから抜け出すにはどうしたらいいでしょうか。簡単です。

For i = 0 to 3
    Wscript.Echo i
    Exit For
Next

出力は次のようになります。

0

スクリプトが Exit For ステートメントに達するとすぐにループから抜け出し、Next ステートメントの次の行に移動します。

詳細

Exit ステートメント – VBScript ランゲージ リファレンス

ページのトップへページのトップへ

来月もアクセスしてください...

今日はもう力が尽きようとしています。休暇の直後ですから、私たちにさほど期待されてはいなかったでしょう。来月は無理かもしれませんが、今後のコラムでいつか、VBScript で使用できる他の種類のループについてご説明しましょう。それまで待てない方は、MSDN で「VBScript ユーザーズ ガイド」 を参照してください。


ページのトップへページのトップへ