これまでの内容は他の言語を習得済みの人に向けて、if文やfor文などを使った"一般的な"プログラミングの書き方を学習してきました。
Powershellではパイプライン
という仕組みを使うことで、これまでの内容をより簡潔に書くことが出来ます。
今回はこのパイプラインの仕組みと、パイプラインと一緒によく使われる標準的なコマンドレットを紹介します。
1. パイプラインとは
パイプラインは、コマンドレットの処理結果や変数を処理した結果を、次の処理(コマンドレット)に渡すための仕組みです。
例えば、以下のforeach文があったとします。
$files = Get-ChildItem -Path D:\powershell\data\sampleFolder1 -File
foreach($file in $files){
Get-Content $file.PSPath
}
この例ではGet-ChildItemでsampleFolder1直下にあるファイルのみのリストをfilesという変数に保存します。
このfilesからforeach文を使って、1件ずつファイルを取得し、その中身を順に表示しています。
この例から分かる通り、filesという変数が二つのコマンドをつなぐ役割を担っています。
一方で、この変数filesを使わずに、2つの処理をつなぐのがパイプラインになります。
上記の処理をパイプラインで書くと、以下の通りになります。
Get-ChildItem -Path D:\powershell\data\sampleFolder1 -File | Get-Content
パイプラインは記号|
で書きます。
このパイプラインを使うことで、|
の左側の処理の結果を|
の右側の処理に渡すことが出来ます。
右側のGet-Contentには引数を渡していないように見えますが、パイプラインを使って左側の処理の結果が渡ってきています。
他のプログラミング言語から入った人は、このパイプラインの考え方に最初は戸惑うかもしれません。
最初なので丁寧に例題を使って学習していきましょう。
例題1-1.
現在のカレントディレクトリを取得するコマンドレットを実行しなさい。
例題1-2.
以下の二つのパスを接続した新しいパスを作成するコマンドレットを実行しなさい。
- D:\powershell\data
- sampleFolder2
※結果がD:\powershell\data\sampleFolder2
になればOK
ヒント
新しいパスを作るには、Join-Pathコマンドレットを使います。
例題1-3.
例題1-1,1-2を参考にして、(現在のカレントディレクトリ)\test
となる新しいパスを作成する処理を実行しなさい。
例題2.
以下の変数path_listには3つのフォルダのフォルダパスが格納されている。
それぞれのフォルダについて、フォルダに格納されている子要素(ファイル、フォルダ)を表示しなさい。
※変数をパイプラインでつないで使用すること
$path_list = "D:\", "D:\powershell", "D:\powershell\data"
ヒント
$path_list | xxxx
と書くことで、xxxxの処理に$path_listの中身を1件ずつ渡せます。
xxxxに何が入るのか考えてみましょう。
2. パイプラインで使用するコマンドレット
最初に見せたパイプラインの例を改めて確認します。
Get-ChildItem -Path D:\powershell\data\sampleFolder1 -File | Get-Content
上記の例では左側の処理の結果は複数のファイルとなります。
この場合、右側のGet-Contentには複数のファイルが渡され、その1件ずつを順番に処理してくれます。
この例では右側の処理が「ファイルの中身を見る」という簡単なものでしたが、より複雑な処理を行いたい場合があります。
そのような場合に使える便利なコマンドレットを紹介します。
2.1. リストの各要素に対する処理を記述する(ForEach-Object)
ForEach-Object
はリストなどの複数要素がある場合に、それぞれの要素にどのような処理をしたいかを記述するコマンドです。
以下の例を見てみましょう。
$count = 0
Get-ChildItem | ForEach-Object {
Write-Host $_.FullName
$count += 1
}
Write-Host ("ファイル数:" + $count)
上記の例ではGet-ChileItemの結果がパイプライン|
を通って、ForEach-Objectに渡されます。
Foreach-Objectでは、渡された要素1件ずつに対してどのような処理を行うかを記述します。
今回は、①ファイル名をフルパスで表示、②ファイル数をカウント の2つを行うことにしました。
このようにForEach-Objectを使うことで、1つのコマンドレットでは実現できない複雑な処理を定義できます。
重要
ForEach-Objectで処理する各要素は$_
という変数に格納されています。
これは自動変数といって、powershell側が勝手に用意してくれる変数です。
例題3.
以下の変数の値の合計値をパイプラインとForEach-Objectを使って求めなさい。
$array = 1..10
例題4.
以下のコマンドを実行しなさい。
その後、ForEach-Objectを使って、以下のコマンドのヘルプを取得しつつ、コマンドの数が何件あるかカウントしなさい。
Get-Command -Name Get-Loca*
2.2. リストから要素を絞り込む
例えば、Get-ChildItemにはファイルのみ取得、フォルダのみ取得などの絞り込みを行うための引数が定義されています。
しかしながら、ファイルサイズが10MB以下のファイルのみ取得などの細かな条件で絞り込むなど、標準のコマンドレットのオプションでは定義できないもの or 書きづらいものがあります。
この場合の解決策の1つはForEach-Object内でif文を使って絞り込むことですが、Where-Object
を使うことでより見通しが良く記述できる場合があります。
まずは以下の処理と処理結果を確認しましょう。
PS D:\powershell\data\sampleFolder1> Get-ChildItem D:\powershell\data\sampleFolder1
ディレクトリ: D:\powershell\data\sampleFolder1
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2022/08/11 7:24 9180 sample2.txt
-a---- 2022/08/10 14:45 24 sample3.txt
-a---- 2022/08/12 7:32 838 sample4.log
-a---- 2022/08/12 7:33 14 sample5.py
上記はsampleFolder1の中身を確認するためのコマンドです。
Lengthはファイルサイズ(バイト)になります。
ファイルサイズが100バイト以上のものを絞り込む場合、Where-Obectを使って以下のように書きます。
Get-ChildItem D:\powershell\data\sampleFolder1 | Where-Object {$_.Length -ge 100}
Where-Objectの中身にはtrue か falseで判断できる条件式を書きます。
つまり、if文の条件式に書く内容を書くと、パイプラインで渡されたデータから、条件に合致するものを絞り込む仕組みです。
また、Where-Objectで絞り込んだ結果は、さらにパイプラインで渡すことが出来ます。
Get-ChildItem D:\powershell\data\sampleFolder1 |
Where-Object {$_.Length -ge 100} |
ForEach-Object { Write-Host $_.FullName }
処理が長くなる場合は、無理に1行で書かず、|
の後で改行を入れましょう。
例題5.
以下の処理結果から、ファイルの拡張子が.txtであるものを絞り込みなさい。
Get-ChildItem D:\powershell\data\sampleFolder1
ヒント
- ファイル名は、-Nameで取得可能。
- 文字列 -Like 検索文字列 でワイルドカードを使ったあいまい検索が可能
例題6.
配列Pathsには、ファイルのパスが格納されている。
この中から、実際に存在するパスのみを抜き出しなさい。
$Paths = "D:\powershell\data\sample1.log", "D:\powershell\data\sample1.txt", "D:\powershell\data\sample11.txt"
ヒント
パスが存在するかどうかは、Test-Pathコマンドレットを使って調べることが出来ます。
Where-Objectの中でTest-Pathを使いましょう。
2.3. リストを並び替える
取得したデータを並び替えるコマンドレットはSort-Object
になります。
Get-ChildItem -Path D:\powershell\data\sampleFolder1 | Sort-Object
出力結果が複数ある場合、Sort-Objectによって順番を並び替えることが出来ます。
デフォルトでは、並び順はName属性(ファイル名)の昇順です。
別の属性を使って並び替えたい場合、-Property
を指定します。
以下は、Length属性(=ファイルサイズ)で並び替えた例です。
Get-ChildItem -Path D:\powershell\data\sampleFolder1 | Sort-Object -Property Length
また、降順に並び替えたい場合は、-Descending
を付けます。
Get-ChildItem -Path D:\powershell\data\sampleFolder1 | Sort-Object -Property Length -Descending
例題7.
以下のコマンドレットの出力結果を更新日時(LastWriteTime)の降順に並び替えなさい。
Get-ChildItem -Path D:\powershell\data\sampleFolder1
3. 最後に
パイプラインはPowershellの中でも特に重要な、奥が深い機能です。
この資料ですべてを説明することはできないので、是非とも公式のマニュアルを読むことをお勧めします。
パイプラインについて - Microsoft
Prev : 08. 文字列、パス文字列の操作
Next : 10.関数