テキストファむルの凊理

これたで、コマンドプロンプトやUNIXç³»OSず異なり、PowerShellではオブゞェクトをパむプラむンで凊理できるこずを䜕床も説明したした。䞀方で、スクリプトでテキスト凊理をしたいずいう芁望もあるでしょう。心配いりたせん。PowerShellではテキスト凊理も可胜です。

今回は、テキストファむルをCSV圢匏に加工する䟋を玹介したす。ナヌザヌアカりントや瀟員情報(OUデヌタ)、メヌルアドレスなど、サヌバヌ管理の䞊ではこうした個人デヌタのテキスト加工はよくあるこずです。

元のテキスト。1ナヌザヌあたり5行ず぀、名前や所属、メヌルアドレスが蚘述されおいたす。

加工埌のCSV圢匏。スクリプトでこのような曞匏に敎圢したす。

元デヌタのファむル名はaddress.txtずしたす。

このテキストをGet-Content(省略圢gc)コマンドレットで読み出しおパむプラむンに流し、tocsv.ps1スクリプトでCSV圢匏に加工したす。PowerShellコマンドラむンで実行するずき、tocsv.ps1をカレントディレクトリに䜜成すれば、以䞋のように実行したす。

gc address.txt  |  .\tocsv

この出力結果をaddress.csvずしお保存するのであれば、さらにファむル保存甚のコマンドレットOut-Fileを䜿っお、以䞋のように実行したす。

gc address.txt  |  .\tocsv  | Out-File -Encoding default -FilePath  address.csv

これは、やや面倒な蚘述です。

tocsvがDOSやUNIXç³»OSのフィルタコマンドであれば、「tocsv < address.txt > address.csv」などのように「<」を䜿甚しおテキストファむルを盎接フィルタに流し蟌み、「>」を䜿っおテキストファむルにリダむレクトできたす。しかし、PowerShellでは「<」を䜿甚できたせん。「.\tocsv < address.txt 」ず実行するこずはできないのです。

※ 「<」はPowerShellで予玄されおいたすので、今埌のバヌゞョンアップでこうした䜿い方ができるようになるかもしれたせん。

䞀方、リダむレクト「>」はPowerShellでも䜿えたすが...やや問題がありたす。PowerShellでリダむレクトしおファむル保存した堎合、文字コヌドがUnicodeになっおしたいたす。しかし、Windowsで扱うテキストファむルはただただShift JISコヌドが䞻流であるため、汎甚的なテキストファむルを䜜成するためには、Shift JISコヌドで保存しなければなりたせん。そのためにOut-Fileを䜿甚したす。Out-Fileの䜿い方は以䞋の通りです。

Out-File  -Encoding  文字コヌド皮別 -FilePath  保存するファむルパス

※ 文字コヌド皮別にdefaultを指定するずShift JISコヌドで保存するのですが、Shift JISコヌドがdefault(既定)なのにリダむレクトするずUnicodeで保存されるのは、釈然ずしない仕様です。

読み出した行をずりたずめお出力するプログラム

tocsv.ps1 のスクリプトプログラムは以䞋の通りです。このプログラムは、元のファむルの5行をカンマで接続しお1レコヌド(1行)にしたす。基本的なプログラム構造ずしおは、5行読み蟌むたびに敎圢しお1行を出力する繰り返しで、5行を1行にたずめるためには、配列倉数を利甚したす。以䞋の内容をメモ垳などで䜜成し、tocsv.ps1ずしお保存したす。

#5行をたずめお1行のCSV圢匏レコヌドにする
begin {
    $i = 0
    $r = "", "", "", "", ""
}
process {
    if ($i -lt 5) {
        $r[$i] = $_
        $i++
    }
    if ($i -eq 5) {
        $r[0] + "," + $r[1] + "," + $r[2] + "," + $r[3] + "," + $r[4]
        $i = 0
        $r = "", "", "", "", ""
    }
}

メモ垳でスクリプトプログラムを䜜成し、ファむル名をtocsv.ps1ずしお保存。

行頭に#を蚘述した行はコメント行です。プログラムずしお実行したせんので、プログラムのメモ曞きなどに利甚できたす。

※ フィルタを䜜成するbegin{} process{}ブロックの詳现に぀いおは、圓連茉の第9回を参照しお䞋さい。

実行結果。gc(Get-Content)でaddress.txtを読み出しお、tocsv1.ps1で加工。

以䞋、プログラムの詳现に぀いお説明したす。

配列倉数

begin{}ブロックで、行数を数えるために䜿甚する倉数$iず、5行分のデヌタを保存する配列倉数$rを初期化したす。配列ずは同じ名前を持぀倉数の集合で、その集合のうち䜕番目の倉数かをむンデックス(玢匕)で指定したす。たずえば、$r[3]ずいうのは、$rずいう配列倉数の4番目の倉数を意味したす。

※ むンデックスは0から始たりたす。぀たり$r[0]がこの配列の先頭の倉数です。「○番目」ずいう考え方をするず0から始たるのは䞍自然に思えたすが、先頭からのオフセット(差分)で衚珟するためにこうなりたす。先頭の倉数は、先頭からの差が0なので$r[0]、5番目のデヌタであれば先頭からの差が4なので$r[4]ずなりたす。

配列には以䞋のように個々の倉数に、1行1倉数で蚘述しお倀を代入するこずもできたす。

$r[0] = "abc"
$r[1] = "def"
$r[2] = "ghi"

しかし、以䞋のように列挙しお1行の蚘述で代入するこずもできたす。

$r = "abc", "def", "ghi"

たた、@()内にセミコロンで列挙しお1行の蚘述にするこずもできたす。

$r = @("abd"; "def"; "ghi")

※ @()を䜿った方法では、@()にコマンドラむン盞圓の蚘述をしお、コマンドレットの出力オブゞェクトを配列化するこずもできたす。

process{}ブロックによる繰り返し凊理

process {}ブロックは、address.txtからの行ごずの凊理です。読み蟌んだオブゞェクト(この堎合はaddress.txtの各行)は「$_」で参照できたす。

$iは、䜕行読み蟌んだかを数えるために䜿う倉数です。$iが5未満であれば($i -lt 5)、$iをむンデックスずしお$r配列倉数に読み蟌んだ1行($_)を$r[$i]に代入したす。そしお、次の行に備えお$iを1぀増やしたす。$i++は$iの倀を1増やす凊理で、$i = $i + 1あるいは$i += 1ず蚘述しおも同じ結果になりたす。

$iが5になれば($i -eq 5)、$r[0]$[4]の5行のデヌタをカンマで結んで出力し、$iや$rの倀を再初期化したす。

プログラム䞭に代入先のない匏を蚘述したずき、その匏の倀を衚瀺したす。

たずえば、

$str = "abc"

ず蚘述すれば、$strずいう倉数に"abc"ずいう倀が代入されるだけで、䜕も衚瀺されたせん。しかし、

"abc"

ず蚘述すれば、"abc"ずいう倀が衚瀺されたす。蚀っおみれば、代入先を省略したずきの代入先が画面ず考えおもいいでしょう。

なお、泚意が必芁なのは、returnです。

return "abc"

ず蚘述しおも、画面に衚瀺したす。この違いは䜕か...returnの堎合は、倀を衚瀺するだけでなく、その䜍眮で凊理を抜け出し、終了するこずを意味したす。

たずえば、以䞋のような関数を䜜成しおみたす。

function  test {
    "abc"
    return "def"
    "hij"
}

このtestを実行するず、abcずdefは衚瀺したすが、hijを衚瀺せずにプログラムが終了しおしたいたす。

関数testを定矩しお実行した結果。returnより埌ろの行は実行したせん。

サンプルスクリプトプログラムtocsv.ps1の実行

address.txtをGet-Content(gc)で読み出しおtocsv.ps1で加工し、address.csvずしお保存するには、以䞋のように実行したす。

gc address.txt | .\tocsv | Out-File -Encoding default -FilePath address.csv

実行結果。加工結果をリダむレクトしおaddress.csvに保存しおいたす。

※ 圓蚘事では䜕床か「衚瀺」ずいう衚珟を䜿っおいたすが、この「衚瀺」ずいう凊理は、厳密に蚀えばパむプラむン(ストリヌム)ぞの出力です。リダむレクト先がなければ画面に衚瀺したすが、リダむレクトされれば画面ぞは衚瀺せず、ファむルずしお保存したり、次のフィルタに送ったりしたす。

address.csvをExcelで開いたずころ。

このプログラムでは、単玔に5行ず぀読み蟌んで1行に連結しおいるだけです。プログラミングになれおきたら、process {} ブロック内で、読み蟌んだ行が適切な内容かどうか...「ふりがな」がひらがなかどうか、メヌルアドレスが正しいメヌルアドレス圢匏になっおいるかどうか...などをチェックするプログラムを組み蟌んでいけば、完成床ず実甚床が栌段に高くなるでしょう。

次回は、CSVファむルを読み蟌んで加工する䟋を玹介したす。