前回のプログラム
前回はGet-FileInformationの枠組みを紹介しました。引き続き、forやswitchについて解説します。
1:$helpmessage = true # ヘルプを表示するかどうかのフラグ
2:
3:for ($i = 0; $i -lt $args.length; $i++)
4:{
5: switch($args[$i])
6: {
7: "today" {
8: # 今日のファイル一覧を表示
9: $helpmessage = false
10: }
11: default {
12: # 何もしません
13: }
14: }
15:}
16:
17:if ($helpmessage)
18:{
19: #ヘルプメッセージを表示
20:}
forによる繰り返し構文
3~15行では、forを使って、コマンドラインで指定されたパラメータを1つずつチェックする繰り返し構文です。
※ forによる繰り返し構文を、forループ(輪)と呼びます。
forは繰り返すたびに値が増える(あるいは減少する)変数を使って、同じ処理を繰り返すときに便利な構文です。使い方は以下の通りです。
for (初期値; 繰り返し条件; 値の増加または減少) { 繰り返す処理 }
今回のプログラムでは、変数iをインデックス(繰り返しを判定する値)として使います。最初に$i = 0でiの値を0に初期化します。
繰り返し条件は、{繰り返し処理}の部分を実行する条件です。$i -lt $args.lengthが成立するとき...つまりiの値がオプションパラメータの数未満の時に{繰り返し処理}(4~15行)を実行します。
$i++は、$i = $i + 1と同じで、iの値に1を加えます。
注意点は、$args.lenthの値(引数の数)が0のときは、最初から$i -lt $args.lengthの条件を満たさないので、繰り返し処理は「1度も」実行しません。また、iの値が$args.lengthに等しくなったとき、もはや繰り返し処理は実行しません。
switchによる条件処理
switchは、変数などの値を評価して、いくつかの処理に分岐する条件分岐構文です。条件分岐と言えば、基本はif構文。あらゆる条件分岐処理は、if構文を使って記述できます。しかし、あまりにもifが積み重なって複雑怪奇になっては見通しが悪いので、switchのようなパターン化された条件分岐構文も用意されています。
switchの構文は以下の通りです。
switch (評価される値)
{
条件1 {条件1が成立したときに実行するプログラム}
条件2 {条件2が成立したときに実行するプログラム}
:
条件x {条件xが成立したときに実行するプログラム}
default {上記のどの条件も成立しなかったら実行するプログラム}
}
なお、defaultの処理が不要な場合でも、switch構文のブロック内には「default {}」を記述する必要があります。
たとえば、変数iの値が整数である場合、以下のようなプログラムを作成すると、iの値が1のとき「一」、2のとき[二]、3のとき「三」、それ以外の時「不明」を表示します。
switch ($i)
{
1 { Write-Host "一"}
2 { Write-Host "二"}
3 { Write-Host "三"}
default { Write-Host "不明"}
}
今回のプログラムでは、Get-FileInformationの実行時に指定されたコマンドラインパラメータforループで1つずつチェックします。そのforループの中で、コマンドラインパラメータ($args[$i])を順番にswitch構文で検証します。
$args[$i]の値が「today」のとき、今日のファイルを表示するための処理を行います(7~10行目)。それ以外の時、ヘルプを表示することにします(defaultの処理...11~13行目)。なお、既定の設定で、文字列評価で大文字小文字を区別しませんので、「today」、「Today」、「TODAY」すべて同じと見なします。
todayを評価するだけであれば、単純にifを使った方が簡単なのですが...、このプログラムは、今後、todayだけでなく、yesterday、lastweekなどにも対応しなければなりません。これからのプログラム拡張に備えて、多くのオプションに対応するためにswitch構文を使用します。
今日のファイルを表示
ここまでのプログラムを完成させます。今のところ、today以外のオプションパラメータは使用できません。
1:#ファイル情報一覧プログラム Ver.0.1
2:#オプション
3:# today
4:
5:#「今日」の開始時間と終了時間を算出
6:function TodayPeriod
7:{
8: $date1 = Get-Date -Hour 0 -Minute 0 -Second 0
9: $date1
10: $date1.AddDays(1)
11:}
12:
13:# $period 開始時間と終了時間を保持する配列変数
14:$helpmessage = $true # ヘルプを表示するかどうかのフラグ
15:
16:#オプションを確認
17:for ($i = 0; $i -lt $args.length; $i++)
18:{
19: switch($args[$i])
20: {
21: "today" { # 今日のファイル一覧を表示
22: $helpmessage = $false
23: $period = TodayPeriod
24: }
25: default {
26: # 何もしません
27: }
28: }
29:}
30:
31:#ヘルプを表示するか、ファイル一覧を実行
32:if ($helpmessage)
33:{
34: Write-Output "Get-FileInformation Ver.0.1 - ファイル一覧コマンド"
35: Write-Output ""
36: Write-Output "使用方法"
37: Write-Output "Get-FileInformation <オプション>"
38: Write-Output "オプション一覧"
39: Write-Output "today - 今日のファイルを表示。"
40:} else {
41: Get-ChildItem -Recurse | `
42: Where-Object `
43: { ($_.LastWriteTime -ge $period[0]) -and ($_.LastWriteTime -lt $period[1]) }
44:}
※ 上記のプログラムに関しては、掲載当初、43行目の「$period[0]」と「$period[1]」を、それぞれ「$time[0]」「$time[1]」と表記しておりましたが、誤りでしたので修正させていただきました。ご迷惑をおかけした皆様に深くお詫び申し上げます。
テキストファイルに行番号を付ける
当連載でPowerShellのスクリプトプログラムに行番号を付けていますが、原稿執筆時に使っているのが、以下のスクリプトです。
1:$lineno = 1
2:foreach ($l in $input)
3:{
4: $lineno.ToString() + ":" + $l
5: $lineno++
6:}1行目で行番号を1に初期化しています。
2行目のinputはパイプラインから入力されたオブジェクトを意味しており、foreach($l in $input)でinputから1行ずつ取り出してlに入れ、{}内の処理を繰り返します。全ての行を処理すると終了します。
4行目、linenoは数値オブジェクトなので、ToString()メンバ関数を使って文字列化してから、「:」や入力された行の値と結合します。
5行目でlinenoの値を1つ増加します。
このスクリプトプログラムをLineNo.ps1として保存すれば、以下のように実行して、Get-FileInfo.ps1のプログラムに行番号を付け、Get-FileInfo.txtに保存できます。
Get-Content Get-FileInfo.ps1 | .\LineNo.ps1 > Get-FileInfo.txt
Get-Content(省略形gc)は、コンテンツ内容(テキストファイルの中身など)を出力するコマンドレットです。