マイナビニュースマイナビ

PowerShell 7をシェルスクリプトとして使う パイプラインを使う

【連載】

PowerShell Core入門 - 基本コマンドの使い方

【第150回】PowerShell 7をシェルスクリプトとして使う パイプラインを使う

[2021/05/28 08:00]後藤大地 ブックマーク ブックマーク

今回は、本連載でこれまで作ってきたPowerShellスクリプトにパイプラインの処理を加えてみよう。スクリプトはパイプラインで使えるようにすることで、より便利なものになる。サンプルで作っているスクリプトの場合にはあまり恩恵はないのだが、作り方の例としてご覧いただければと思う。

パイプラインに対応させる

前回の成果物「test-d_14.ps1」は次の通りだ。PowerShellスクリプトとして、かなりそれらしい体裁になってきた。「Get-Help」に対応したヘルプメッセージも追加されている。

#!/usr/bin/env pwsh

<# 
.SYNOPSIS
ディレクトリパスが存在するかどうかを判定。

.DESCRIPTION
指定されたパスがディレクトリパスであり、かつ、存在するかどうかを判定する。

.PARAMETER DirectoryPath
ディレクトリパスを指定。

.PARAMETER Help
ヘルプメッセージを表示。

.INPUTS
なし。パイプには対応していない。

.OUTPUTS
System.Boolean。ディレクトリパスが存在する場合にTrue、そうでない場合にFalse。

.EXAMPLE
PS> .\test-d .\Documents\
True

.EXAMPLE
PS> .\test-d .\Documents-non-exists\
False

.LINK
Test-Path
#>

#====================================================================
# 引数
#====================================================================
Param(
    [string]$DirectoryPath,     # ディレクトリを指定
    [switch]$Help           # ヘルプを表示
)

if ($Help -Or -Not $DirectoryPath) {
    Get-Help $PSCommandPath
    exit 1
}

#====================================================================
# ディレクトリパスの存在確認
#====================================================================
if (Test-Path -PathType Container -Path $DirectoryPath) {
    # 指定されたパスはディレクトリであり、存在している。
    $True
} else {
    # 指定されたパスはディレクトリではない。
    if (Test-Path -PathType Leaf -Path $DirectoryPath) {
        # 指定されたパスはファイル。
        $infomsg = "$DirectoryPath : " `
            + "ファイルです。"
    } else {
        # 指定されたパスは存在しない。
        $infomsg = "$DirectoryPath : " `
            + "そのようなディレクトリは存在しません。"
    }
    Write-Host $infomsg
    $False
}

ヘルプメッセージにも書いてあるが、このスクリプトはパイプラインからの入力に対応していない。引数にディレクトリパスを指定して利用することを想定している。試しにパイプライン経由でディレクトリパスを渡すと、次のようにヘルプが表示される。これは引数が何も指定されていないため、動作としてヘルプを表示する状態になっているからだ。

test-d_14.ps1はパイプラインからの入力には対応していない

これまで連載で取り上げてきたように、PowerShellでは「$input」がパイプラインの入力にアクセスするものになる。「$input」を使ってパイプライン経由でのディレクトリパスも指定できるようにしてみよう。

パイプラインからディレクトリパスを取得して動作

先に今回の成果物「test-d_15.ps1」を掲載しておく。次のように書き換えを行った。

#!/usr/bin/env pwsh

<# 
.SYNOPSIS
ディレクトリパスが存在するかどうかを判定。

.DESCRIPTION
指定されたパスがディレクトリパスであり、かつ、存在するかどうかを判定する。

.PARAMETER DirectoryPath
ディレクトリパスを指定。

.PARAMETER Help
ヘルプメッセージを表示。

.INPUTS
ディレクトリパス。引数でディレクトリパスが指定されていない場合に使われる。

.OUTPUTS
System.Boolean。ディレクトリパスが存在する場合にTrue、そうでない場合にFalse。

.EXAMPLE
PS> .\test-d .\Documents\
True

.EXAMPLE
PS> .\test-d .\Documents-non-exists\
False

.EXAMPLE
PS> dir | .\test-d
True

.LINK
Test-Path
#>

#====================================================================
# 引数
#====================================================================
Param(
    [string]$DirectoryPath,  # ディレクトリを指定
    [switch]$Help          # ヘルプを表示
)

if ($Help) {
    Get-Help $PSCommandPath
    exit 1
}
# 引数でディレクトリが指定されていない場合、パイプからディレクトリ
# パスの取得を試みる。
if (-Not $DirectoryPath) {
    $DirectoryPath = @($input)[0]

    if (-Not $DirectoryPath) {
        Get-Help $PSCommandPath
        exit 1
    }
}

#====================================================================
# ディレクトリパスの存在確認
#====================================================================
if (Test-Path -PathType Container -Path $DirectoryPath) {
    # 指定されたパスはディレクトリであり、存在している。
    $True
} else {
    # 指定されたパスはディレクトリではない。
    if (Test-Path -PathType Leaf -Path $DirectoryPath) {
        # 指定されたパスはファイル。
        $infomsg = "$DirectoryPath : " `
            + "ファイルです。"
    } else {
        # 指定されたパスは存在しない。
        $infomsg = "$DirectoryPath : " `
            + "そのようなディレクトリは存在しません。"
    }
    Write-Host $infomsg
    $False
}

書き換えたスクリプトの動作を見てみよう。標準入力から渡したデータの1つ目をパスとして取り出し、それがディレクトリパスであり、存在するかどうかを判定していることがわかる。

test-d_15.ps1の実行サンプル - パイプラインからディレクトリパスを読み取って動作している

スクリプトの挙動が変わったので、ヘルプメッセージも書き換えてある。次のようにして確認できる。

更新されたヘルプメッセージを確認

更新されたヘルプメッセージを確認

では、どのように書き換えたのかを見ていこう。前回のスクリプトでは、引数に-Helpパラメータが指定されていた場合か、ディレクトリパスが指定されていなかった場合に、次のようにヘルプメッセージを表示してプログラムを終了するように処理を組んでいた。

if ($Help -Or -Not $DirectoryPath) {
    Get-Help $PSCommandPath
    exit 1
}

今回はここを、「ディレクトリパスが指定されていない場合には、パイプラインからパスを読み込む」という処理に変更する。まず、-Helpパラメータが指定されていたときの動作を次のように変更する。

if ($Help) {
    Get-Help $PSCommandPath
    exit 1
}

次に、「引数にディレクトリパスが指定されていなかった場合に、パイプラインからディレクトリパスを取得して処理する」という処理を追加する。ここでは次のように追加した。

if (-Not $DirectoryPath) {
    $DirectoryPath = @($input)[0]

    if (-Not $DirectoryPath) {
        Get-Help $PSCommandPath
        exit 1
    }
}

パイプラインから何も入力が得られなかった場合には、これまでと同じようにヘルプメッセージを表示して処理を終了させている。

動作は書いてある通りだが、「@($input)[0]」という書き方がポイントだ。こう書くと「『$input』を配列として扱い、その1つ目の要素を持ってくる」という処理にすることができる。ここでは処理を簡素化したいので、このようにパイプラインの1つ目のデータのみを取り出している。

動作が変わっているのでヘルプも書き換えが必要だ。前回のスクリプトでは、パイプラインの入力データについては次のように説明を行っていた。

.INPUTS
なし。パイプには対応していない。

今回パイプラインからの入力に対応したので、この部分を次のように書き換える。

.INPUTS
ディレクトリパス。引数でディレクトリパスが指定されていない場合に使われる。

さらに、実行サンプルとして次のような動作も追加した。

.EXAMPLE
PS> dir | .\test-d
True

この書き換えで、今回目的としたディレクトリパスをパイプラインから持ってくる処理の完了だ。

パイプラインも使っていこう

これまでWindows系のコマンドばかり扱っていたのであれば、パイプラインでコマンドをつなげて処理するといったことはあまり行うことがなかったかもしれない。パイプラインはUNIX系のOSでよく使われる方法だ。慣れるととても便利なものなので、ぜひとも使えるようにしていただきたい。

ただし、UNIX系OSのパイプラインと、PowerShellのパイプラインは根本的に異なるメカニズムで動作するものである、ということは覚えておいたほうがよいと思う。UNIX系OSのパイプラインは動作が高速でマルチコアを有効に使えるが、PowerShellはあくまでも順番に処理するための方法にすぎない。PowerShellでパイプラインをたくさん使ったからとして、パフォーマンスが向上するわけではない点には注意が必要だ。

※ 本記事は掲載時点の情報であり、最新のものとは異なる場合がございます。予めご了承ください。

一覧はこちら

連載目次

もっと知りたい!こちらもオススメ

【連載】RPA入門 - ツールで学ぶ活用シーン

【連載】RPA入門 - ツールで学ぶ活用シーン

AIには、ルールベース、機械学習、深層学習(ディープラーニング)の3つのレベルがあり、レベルが上がるに連れてより高度な人工知能を実現しますが、AIのスピンオフという位置付けで、Digital Labor(仮想知的労働者)によるホワイトカラー業務の自動化を実現するRPAが注目されています。

関連リンク

この記事に興味を持ったら"いいね!"を Click
Facebook で TECH+ の人気記事をお届けします
注目の特集/連載
[解説動画] Googleアナリティクス分析&活用講座 - Webサイト改善の正しい考え方
Slackで始める新しいオフィス様式
Google Workspaceをビジネスで活用する
ニューノーマル時代のオウンドメディア戦略
ミッションステートメント
次世代YouTubeクリエイターの成長戦略
IoTでできることを見つけるための発想トレーニング
教えてカナコさん! これならわかるAI入門
AWSではじめる機械学習 ~サービスを知り、実装を学ぶ~
Kubernetes入門
SAFeでつくる「DXに強い組織」~企業の課題を解決する13のアプローチ~
マイクロサービス時代に活きるフレームワーク Spring WebFlux入門
AWSで作るマイクロサービス
マイナビニュース スペシャルセミナー 講演レポート/当日講演資料 まとめ
セキュリティアワード特設ページ

一覧はこちら

今注目のIT用語の意味を事典でチェック!

一覧はこちら

会員登録(無料)

ページの先頭に戻る