この連載では、Microsoftが提供している新しいシェル、Windows PowerShellの使い方を解説します。今回は、フィルタ、スクリプトブロック、変数のスコープについて取り上げます。

はじめに

 この連載では、Microsoftが提供している新しいシェル「Windows PowerShell」の使い方を解説します。今回は、フィルタ、スクリプトブロック、変数のスコープについて説明します。

対象読者

  • Windows PowerShellでコマンドレット操作ができる方
  • 何らかのプログラミング経験があればなお良い

必要な環境

  • Windows PowerShell

フィルタ

 PowerShellには、関数とは別にパイプを通して受け取ったオブジェクトを処理するフィルタと呼ばれるものがあります。書式は関数とほぼ一緒なのですが、functionの代わりにfilterキーワードを使用します。

filter <フィルタ名> (引数) {実行するスクリプト}

 関数と同様、結果をreturnで返すことも可能です。

フィルタの利用例

 唐突ですが、ここで問題です。「現在稼働しているサービス一覧を取得してください」と言われたらどうしますか?

 解答例を示します。

PS > Get-Service | Where { $_.Status -eq "Running" }

Status   Name               DisplayName
------ ---- -----------
Running AeLookupSvc Application Experience
Running AppHostSvc Application Host Helper Service
Running AudioEndpointBu... Windows Audio Endpoint Builder
Running Audiosrv Windows Audio
Running BFE Base Filtering Engine
:
: ≪長いので省略≫
:

 Get-ServiceコマンドレットとWhereを使用してステータスが"Running"のものをフィルタしています。この $_.Status -eq "Running" はフィルタ化することが可能です。

 では、フィルタ名を StsRunning としてフィルタを作成してみましょう。

PS > filter StsRunning {
>> if ( $_.Status -eq "Running" )
>> {
>> return $_
>> }
>> }
>>

 こうして作成したフィルタの使用方法は簡単で、パイプの後ろに記述するだけです。

PS > Get-Service | StsRunning

Status   Name               DisplayName
------ ---- -----------
Running AeLookupSvc Application Experience
Running AppHostSvc Application Host Helper Service
Running AudioEndpointBu... Windows Audio Endpoint Builder
Running Audiosrv Windows Audio
Running BFE Base Filtering Engine

 このように、よく使用するフィルタ条件は、専用のフィルタを作成しておくと便利です。

 なお、フィルタはコンソール上で作成すると、PowerShell終了時に消滅してしまうので、プロファイルに登録することをお奨めします(連載第7回の「関数をプロファイルに追加する」参照)。

 関数とフィルタの違いをまとめると、次のとおりです。

  • 関数は、パイプで受け取ったオブジェクトを一度に処理する
  • フィルタは、パイプで受け取った個々のオブジェクトごとに実行する

スクリプトブロック

 「スクリプトブロック」とは、他の言語で言う匿名関数やラムダ式に相当するものです。PowerShellにおいては中括弧{}で囲まれたスクリプトコードに過ぎません。

 例えば

PS > 1..10 | foreach { Write-Host $_ }

 と記述したときの、{ Write-Host $_ }はスクリプトブロックです。

スクリプトブロックを変数に代入する

 スクリプトブロックは、変数に代入することもできます。

 例えば下記は、変数$aを3倍するというスクリプトブロックを変数$sに代入したことになります。

PS > $s = { $a * 3 }

スクリプトブロックを実行する

 では、スクリプトブロックを実行するにはどうすれば良いでしょうか?

PS > $s

 上記のように変数名を入力して[Enter]を押すだけでは実行することができません。

 スクリプトブロックを実行するには、下記のように &演算子を使用します。

PS > $a =2
PS > & $s
6

 スクリプトブロックではparamによる引数の受け取りが可能です。下記のスクリプトブロックは、paramで引数を1つ受け取り、引数を3倍します。

PS > $script = { param($a); $a * 3 }

 実行方法は、先ほど説明したように&演算子を使用して変数名を指定し、その後に引数として渡す値を記述します。

PS > & $script 5
15

 もう1つ、$argsによる値の受け取りも可能です。先ほどのスクリプトブロックを$argsで書き換えてみたのが下記です。

PS > $script = { $args[0] * 3 }

 実行方法は、paramのときと同様です。

PS > & $script 5
15

変数のスコープ

 まずは、下記スクリプトで変数のスコープについてみていきたいと思います。

Scope1.ps1
$a = 3

function Sample1
{
Write-Host "1)変数`$a=$a"
$a = 5
Write-Host "2)変数`$a=$a"
} #関数 sample1を実行
Sample1
Write-Host "3)変数`$a=$a"

 このスクリプトを実行すると結果は下記のようになります。

PS C:\Work> ./Scope1.ps1
1)変数$a=3
2)変数$a=5
3)変数$a=3

 この動作について図で解説します。

 

 スクリプトの1行目で変数$aを作成し、3を代入しています。この変数はスクリプト内で有効です(1行目から12行目までがこの変数のスコープ。スクリプトスコープという)。

 次に、11行目で関数Sample1を呼び出します。この呼び出しにより5行目が実行され、ここの変数$aでは1行目で代入した値「3」が表示されます。

 次に6行目で変数$aに「5」を代入していますが、この変数$aは1行目で作成した変数とは別のものです。関数Sample1内でのみ有効で、生存期間は6行目から7行目までとなります。これをローカル変数と呼びます。

 関数Sample1の実行が終わり、最後に12行目が実行されるわけですが、ここの変数$aは1行目で作成した変数$aであり、結果として「3」が表示されます。

 以上より、次のことが分かります。

  • 関数の外側で作成した変数は、スクリプトファイル内すべてが有効範囲である。
  • 関数内で作成した変数は、関数内のみが有効範囲である。
  • 関数の外で作成された変数と、関数内で作成した変数が同一名の場合は関数内で作成した変数が優先されるが、スクリプトスコープを持つ変数を上書きしない。

スクリプトスコープを持つ変数を参照する

 先ほどの例で、$aという同じ名前でスコープの異なる2つの変数を使用しました。関数内でローカル変数$aが優先されることは説明したとおりです。

 では、ローカル変数$aが優先されている状況下の中で、スクリプトスコープを持つ$aを参照するにはどうすれば良いでしょうか? この場合は、script修飾子を使用します。

 例を示します。

Scope2.ps1
$a = 3

function Sample2
{
Write-Host "1)変数`$a=$a"
$a = 5
Write-Host "2)変数`$a=$a"
Write-Host "3)変数`$a=$script:a"
$script:a = 7
Write-Host "4)変数`$a=$script:a"
Write-Host "5)変数`$a=$a"
} #関数 sample2を実行
Sample2
Write-Host "6)変数`$a=$a"

 このスクリプトの実行結果は下記の通りです。

PS C:\Work> ./Scope2.ps1
1)変数$a=3
2)変数$a=5
3)変数$a=3
4)変数$a=7
5)変数$a=5
6)変数$a=7

 このように変数名が重複する場合に、スクリプトスコープを持つ変数を参照するには、$script:aと、キーワードscriptを付加し、スクリプトスコープの変数への参照であることを明示します。

 また、スクリプトスコープの変数へ値を代入してもローカル変数の値は影響を受けないこと、関数を抜けた後の変数の値が変更されていることも確認してください。

 ポイントは次の2点です。

  • 関数内でスクリプトスコープを持つ変数へのアクセスはscript修飾子を使用する。
  • script修飾子を使用して値を書き換えても、同一名称のローカル変数へは影響しない。

 少し複雑なサンプルですが、ぜひ実際に実行して、ローカル変数とスクリプトスコープを持つ変数の違いを理解してください。

プライベートスコープ

 変数のスコープの種類には、プライベートスコープもあります。下記スクリプトで説明します。

Scope3.ps1
$a = 3

function funcA
{
Write-Host "2)$a"
$a = "7"
Write-Host "3)$a"
funcB
} function funcB
{
Write-Host "4)$a"
} Write-Host "1)$a"
funcA
Write-Host "5)$a"

 このスクリプトには2つの関数があり、最初にfuncAを呼び出し、funcAの中からfuncBを呼び出しています。またソース内での1)~5)は分かりやすいように実行順を示しています。

 このスクリプトの実行結果は下記の通りです。

PS C:\Work> ./Scope3.ps1
1)3
2)3
3)7
4)7
5)3

 このスクリプトの動作について図で説明します。

 

 1行目の変数$aはスクリプトスコープを持つ変数となるので、有効期間は赤線の通りでスクリプトファイルの最後までです。

 次に6行目の変数$aですが、この変数はローカル変数となりfuncAが有効期間です。

 さらに、この関数funcAfuncBを呼び出しており、funcAで作成したローカル変数$aの有効期間は青線で示した箇所、つまりfuncBまでおよびます。

 では、funcA内だけで有効なローカル変数を作成したい場合は、どうすれば良いでしょうか?

 これを実現するにはprivate修飾子を使用します。

 下記は「Scope3.ps1」をprivate修飾子を使用して書き換えたものです。funcAのローカル変数のスコープがfuncBに及ばないようにしています(6行目でpraivateキーワードを付加しています)。

Scope4.ps1
$a = 3

function funcA
{
Write-Host "2)$a"
$private:a = "7"
Write-Host "3)$a"
funcB
} function funcB
{
Write-Host "4)$a"
} Write-Host "1)$a"
funcA
Write-Host "5)$a"

 このスクリプトの実行結果は下記の通りです。

PS C:\Work> ./Scope4.ps1
1)3
2)3
3)7
4)3
5)3

 「Scope4.ps1」でのスコープを図で見てみましょう。

 

 privateキーワードを使用したので、funcAのローカル変数$aのスコープは青線の部分となります。

グローバルスコープ

 最後にグローバルスコープを持つ変数について説明したいと思います。グローバル変数は、スクリプトファイルを超えてスコープを持つ変数です。

 下記スクリプトで実験してみたいと思います。

Scope5.ps1
$global:glb_a = 3

function funcA
{
Write-Host "2)$glb_a"
} Write-Host "1)$glb_a"
funcA
Write-Host "3)$glb_a"

 グローバル変数を作成するには、1行目のようにglobal修飾子を使用します。

 このスクリプトの実行結果は下記の通りです。

PS C:\Work> ./scope5.ps1
1)3
2)3
3)3

 スクリプト内で$glb_aというグローバル変数を作成しました。最初に説明したように、グローバル変数はスクリプトファイルを超えてスコープを持つので、スクリプトの実行後にコマンドラインで変数を参照することが可能です。

PS C:\Work> $glb_a
3

 ではグローバル変数のスコープを図で見てみましょう。

 

 グローバル変数のスコープは、「Scope5.ps1」が呼び出された後(水色の矢印)スクリプトが終わるまで有効です。

 さらに、スクリプトが終了し、コンソールウィンドウに戻った後(赤の点線)もグローバル変数は生存し続けます。

 結果として、コマンドラインで$glb_aを確認できたというわけです。

まとめ

 今回は、次の3点について説明しました。

  • フィルタ
  • スクリプトブロック
  • 変数のスコープ

 変数のスコープは説明が長くなってしまいましたが、スクリプト開発を行う上で非常に重要な概念ですので、ぜひ覚えてもらいたいと思います。

 次回は、エラーの取り扱いについて説明します。

Windows PowerShell 入門(8)-関数編3的更多相关文章

  1. Windows PowerShell 入門(7)-関数編2

    この連載では.Microsoftが提供している新しいシェル.Windows Power Shellの使い方を解説します.前回に引き続きPowerShellにおける関数の取り扱いとして.変数と関数のスコ ...

  2. Windows PowerShell 入門(3)-スクリプト編

    これまでの記事 Windows PowerShell 入門(1)-基本操作編 Windows PowerShell 入門(2)-基本操作編 2 対象読者 Windows PowerShellでコマンド ...

  3. Windows PowerShell 入門(2)-基本操作編 2

    前回に引き続きMicrosoftが提供している新しいシェル.Windows Power Shellの基本操作方法を学びます.基本操作編第2弾の今回は.パイプの使用方法を中心としたコマンドレットの操作方 ...

  4. Windows PowerShell 入門(6)-関数編1

    この連載では.Microsoftが提供している新しいシェル.Windows Power Shellの使い方を解説します.今回は.関数の作成基礎と引数.戻り値.Switchパラメータについて説明します. ...

  5. Windows PowerShell 入門(10)-デバッグ編

    対象読者 Windows PowerShellでコマンドレット操作ができる方 何らかのプログラミング経験があればなお良い 必要環境 Windows PowerShell デバッグメッセージの出力 Po ...

  6. Windows PowerShell 入門(9)-エラー編

    対象読者 Windows PowerShellでコマンドレット操作ができる方 何らかのプログラミング経験があればなお良い 必要環境 Windows PowerShell エラーをリダイレクトする リダ ...

  7. Windows PowerShell 入門(4)-変数と演算子

    Windows PowerShellにおける変数と演算子の使用方法について学びます.今回は代表的な演算子として.算術演算子.代入演算子.論理演算子.比較演算子.範囲演算子.置換演算子.ビット演算子.型 ...

  8. Windows PowerShell 入門(1)-基本操作編

    Microsoftが提供している新しいシェル.Windows Power Shellの基本操作方法を学びます.インストール.起動終了方法.コマンドレット.命名規則.エイリアス.操作方法の調べ方について ...

  9. Windows PowerShell 入門(5)-制御構文

    Windows PowerShellにおける制御構文について学びます.数ある制御構文の中でもSwitch文は.他の言語に比べ豊富な機能が用意されています. 対象読者 Windows PowerShel ...

随机推荐

  1. 建立Heapster Influxdb Grafana集群性能监控平台

    依赖于kubenets dns服务 图形化展示度量指标的实现需要集成k8s的另外一个Addons组件: Heapster .Heapster原生支持K8s(v1.0.6及以后版本)和 CoreOS , ...

  2. 【C#】C#获取文件夹下的所有文件

    #基础知识 1.获得当前运行程序的路径 string rootPath = Directory.GetCurrentDirectory(); 2.获得该文件夹下的文件,返回类型为FileInfo st ...

  3. Java Web之Web组件之间的跳转方式

    方法有3种: 第一种:请求转发 我们来写两个类,一个是Servlet1一个是Servlet2 package main.com.vae.forward; import javax.servlet.Se ...

  4. java io系列04之 管道(PipedOutputStream和PipedInputStream)的简介,源码分析和示例

    本章,我们对java 管道进行学习. 转载请注明出处:http://www.cnblogs.com/skywang12345/p/io_04.html java 管道介绍 在java中,PipedOu ...

  5. Hadoop记录-Linux Service

    [Unit] Description=Datanode After=syslog.target network.target auditd.service sshd.service datanode_ ...

  6. java和c#通过esb服务互调用组件

    场景:java和c#写的服务.站点,互相任意调用.实现一切即服务. 解决方案:使用这种轻量级的esb架构,通过tcp通信解决通信传输问题,总线服务解决服务地址问题,契约解决数据交互问题.由于组件封装了 ...

  7. wordcloud制作logo

    准备工作: 1.txt文本(ASCII) 2.参照图(色差大或自行调整扫描参数) 3.pycharm安装wordcloud 源码: from os import path from PIL impor ...

  8. time 模块 与 datetime 模块

    3 print(time.time()) # 时间戳:1487130156.419527 4 print(time.strftime("%Y-%m-%d %X")) #格式化的时间 ...

  9. select监听udp消息

    服务端 #!/usr/bin/python2.6 # -*- coding:utf-8 -*- import json import socket import select def socketse ...

  10. Ganglia 入门介绍及解决fsockopen error: Connection refused问题

    一,问题描述 Ganglia的各个组件安装情况(不是我装的,只知道这些信息): 集群一共有4台机器,分别是192.168.121.34-37.Gmetad.Gweb和httpd 安装在 192.168 ...