6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Powershell入門 - 09. パイプライン

Last updated at Posted at 2022-10-04

これまでの内容は他の言語を習得済みの人に向けて、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.関数

目次へ戻る

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?