この連載では、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. 设计模式_策略模式_在Spring中的应用

    一.理论 在spring中经常有读取配置文件的需求,这里就会用到一个Spring提供的Resource接口 Resource 接口是具体资源访问策略的抽象,也是所有资源访问类所实现的接口.Resour ...

  2. Kafka技术内幕 读书笔记之(三) 消费者:高级API和低级API——消费者消费消息和提交分区偏移量

    消费者拉取钱程拉取每个分区的数据,会将分区的消息集包装成一个数据块( FetchedDataChunk )放入分区信息的队列中 . 而每个队列都对应一个消息流( KafkaStream ),消费者客户 ...

  3. Hadoop记录-NameNode优化

    1.NameNode启动过程 加载FSImage: 回放EditLog: 执行CheckPoint(非必须步骤,结合实际情况和参数确定,后续详述): 收集所有DataNode的注册和数据块汇报. 采用 ...

  4. Mastering Markdown

    What is markdown? Markdown is a lightweight and easy-to-use syntax for styling all forms writing on ...

  5. hdu 2815 Mod Tree (exBSGS)

    http://acm.hdu.edu.cn/showproblem.php?pid=2815 //解 K^D ≡ N mod P #include<map> #include<cma ...

  6. 打印流PrintStream

    打印流PrintStream PrintStream extends OutputStream 1.打印流的特点 只负责数据的输出,不负责数据的读取 与其他的流不同,打印流永远不会抛出IOExcept ...

  7. StringBuilder类

    java.lang.StringBuilder String类代表字符串,他的底层是一个被final修饰的数组,不能改变,字符串是常量,它们的值一旦被创建之后就不能改变,但是字符串缓冲区(String ...

  8. 错误 1 “Entities.PlanPrjEntity.PlanPrjs”不可访问,因为它受保护级别限制

    本人第一次是用List做父类,写了一个类PlanPrjs,如下: class PlanPrj { public int ID { get; set; } public string Name { ge ...

  9. React Native的语法之ES5和ES6

    原文地址:http://www.devio.org/2016/08/11/React-Native%E4%B9%8BReact%E9%80%9F%E5%AD%A6%E6%95%99%E7%A8%8B- ...

  10. JQuery Rest客户端库

    JQuery Rest https://github.com/jpillora/jquery.rest/ Summary A jQuery plugin for easy consumption of ...