コマンドレットのパラメータを列挙してみる。」に基づいた記述が含まれているおそれがあります。2017の24日目です。一般的なプログラミング言語では、文(statement)と式(expression)の違いは、値を返すのが式で、返さないのが文、という説明がされることが多いと思います。PowerShellではこの説明は成り立たたず、文が値を返したりしてるように見えて良く分かりません。3.0のものですが)やAST(ShowPSAstモジュールが便利!)を眺めながら考えてみたので軽くまとめようと思います。文(statement)と式(expression)の定義PowerShellでは言語要素として、文(statement)と式(expression)が明確に定義されています。言語要素の何が文であって、何が式であるかという定義は仕様できちんと決まっていて、ある言語要素が、状況によって文になったり式になったりと変化する、ということはありません。パイプライン、代入、ifやforやfunctionなどは文です。変数、数値/文字リテラル、オブジェクトのメンバ呼び出し、スクリプトブロック、単項または二項算術演算子で構成される式、カンマ演算子で構成される配列などは式です。仕様書での定義と、実際に構築されるASTに齟齬があることはあります。assignment-expressionと書かれています。厳密には、言語仕様書のgrammer節によれば、assignment-expressionはexpressionではなくpipelineであるということになっています(お前は何を言っているんだ)。いずれにせよパイプラインは文であるので、AST通り、代入は文であるという解釈で良いと思います。expressionとはっきり書いてあるんだから代入は式だろ!という意見を否定するものではないです。代入は文であると考えたほうが他の文法と整合性を取りやすいので、そういう立場をとりました。しばたさんが9日目に書かれた記事で取り上げられているように、配列に関しても同様の齟齬があります。いずれにせよ「1,2,3」のような配列は、式と考えて良いと思います。文と式の構造PowerShellには文と式が存在することは分かりました。それを考察するために、具体的にいくつかの文と式の構造を取り上げて見ていきます。ProcessName」みたいな|で繋ぐやつのことでしょ、と思われがちですが、言語仕様上は以下のようなものはすべてパイプラインです。�E算術式をパイプラインでコマンドと繋げたもの要はパイプラインというのは、一般的なプログラミング言語で、;で終わる一文に相当するものと考えればだいたい間違いないと思います。PowerShellだと文末の;は必須ではなく、改行でもOKです。パイプラインは以下のような構造を取ります。[]は省略可能を意味します。代入文すなわち、代入文(後述)を除くパイプラインは1個以上のパイプライン要素から構成されており、複数のパイプライン要素が存在する場合はパイプ演算子|で連結されます。パイプライン要素には式とコマンド(Get-Processとか)が存在します。式は1つ目のパイプライン要素にのみ許可されます。以上を踏まえると、�@、�Dはコマンドのみで構成されるパイプライン、�A、�Bは単独の式のみで構成されるパイプライン、�Eは1つの式とコマンドで構成されるパイプライン、�Cは代入文であることが分かります。代入文はパイプラインなので、文です。代入文は以下のような構造を取ります。文ただし、左辺の式は、変数やプロパティなど、代入が可能な式である必要があります。よって以下のような記述が可能です。右辺には文であれば何でも書けるのですが、実際に代入が行われるのは、パイプライン、if文、for文、switch文といった、パイプラインに値を出力する文と代入文に限られます。ちなみに�Dのようにパイプラインと代入文以外の文を右辺に指定できるようになったのは、PowerShell2.0からです。ところで上記�@や�Aは右辺が式です。代入文の右辺は文じゃなかったの?と思われると思いますが、パイプラインの節で述べた通り、単独の式もパイプラインであり、パイプラインは文なので、三段論法でいくと式は文として扱われることになります。$bの右辺はPipelineAst/CommandExpressionAst/VariableExpressionAstではなく、いきなりCommandExpressionAst/VariableExpressionAstとなっているので、この説明はASTの実装とはかみ合わないかもしれません。AssignmentStatementAst.Rightは確かにStatementAstを取るのですが、CommandExpressionAstはStatementAstから派生しているクラスなので、式の代入は問題なく行えます。代入文は上記�Eのようなことができることから分かる通り、値を返す文ですが、パイプラインには値を出力しません。値は返すがパイプライン出力がないものは、インクリメント演算子で構成される式($a++等)も同様です。if文パイプラインと代入文以外の文は色々あるわけですが、代表的なものとしてif文を取り上げます。シンプルなif文はこういう構造です。{文1文2....}おそらく多くの人が誤解しているのではないかと思いますが、条件節に書くのは式ではなくパイプラインです。パイプラインを実行した結果、出力値がtrue、またはboolに型変換してtrueになる場合に、ブロック内の複数の文が実行されます。よって以下のような記述が可能です。�@と�Aは普通の書き方ですが、実際には、1つの式のみ有するパイプラインを実行し、出力される値が判定されています。条件節はパイプラインなので、当然�Bのような書き方もできるわけです。代入文もパイプラインであるので、�Cの書き方もできてしまい、注意を要します。(if($true){}){}というような書き方はできません。※といっても実はこう書くと文法上はvalidであり、条件節内は「ifコマンド、パラメータ値1($true)、パラメータ値2(スクリプトブロック)」という解釈になってしまいます。{}という書き方はできません。(パーサーもエラーを出す)丸括弧式さて、普通のプログラミング言語だと、()はグループ化や演算子の優先順を変更するのに用いられるものの、別に文法そのものに影響を与えるものではないと思います。多くの場合、ASTでも()の情報はそぎ落とされます。ところがPowerShellでの丸括弧()は文法的な意味を有しており、ASTにもParenExpressionAstとして存在する、立派な式です。丸括弧式の構造は以下の通りです。(パイプライン)これは要するに、「パイプラインに()を付けると式になる」、ということです。()内のパイプラインで出力された値が返される式となります。具体的にどういうところで使うのかを示します。�Cコマンドのパラメータにコマンド実行結果を指定する�@の使い方は普通です。()はパイプラインを生成するので、「(1+3)」は「1つの式のみ有するパイプラインを実行し、パイプラインに値を出力し、その値を返す」という見た目より複雑な処理になります。※少なくともAST上はそうなりますが、実際は何らかの最適化処理が入ってる可能性はあります。代入を重ねる場合には�Aのような書き方は必要ないのですが、代入した結果をパイプラインの出力としたい場合は()を付ける必要があります。この場合、$aに1が代入され、コンソールにも1が出力されます。�Bで挙げている、式を許容するがパイプラインは許容しない言語要素というのは実はあまりないです。前述した通りif文の条件節は式じゃなくて、パイプラインを取るといった案配です。配列や連想配列の要素を取得するインデックス演算子[]は、式のみ許容されます。コマンドなどのパイプラインの出力値を指定したい場合は()が必須となるわけです。ちなみに、()内にはパイプライン以外の文(if文等)は指定できません。複数のパイプラインも指定できず、あくまで1つだけです。※任意の文あるいは複数の文を式としたい場合には、部分式演算子$()または@()を用います。両者とも内部の文がパイプラインに出力した値を返す、「部分式」となります。両者とも複数値が出力されると配列になりますが、@()は出力値が1つでも要素数1の配列を返す点が異なります。まとめ?PowerShellの文と式は厳密に定義されています。文は複数の文と式で構成されるし、式は複数の文と式で構成されています。文や式の構成要素が取る文や式の種類についても、各々、きちんと定義されています。PowerShellにおいて「値を返すか返さないか」、「パイプラインに出力されるかされないか」、「式であるか文であるか」という概念はすべて独立しています。そのため、PowerShellの文とは何である、式とは何である、ということを一言で説明することは難しいんじゃないかと思います。本記事でこれまで述べてきたとおり、「パイプラインは文で、要素として式やコマンドを取りますよ」とか、「ifは文で、条件節にはパイプラインを取りますよ」みたいな、各論でしか表現できないのではないかなぁと、私はそういう結論に至りました。ここまで書いてちゃぶ台をひっくり返すようなことを言いますが、ある言語要素が文であるか式であるか、ここまで仕様書を読んだりASTを追ったりして把握するのは、まあ楽しくなくはないですが、知らなくても別に大丈夫だと思われます。別に、ifの条件節には条件式を書くのだと理解していても不都合は特にないかと。{}」とかの、余分な()を取り除くのには文法の知識が役立ちます。それ程問題にはならないかもしれません。2.0を利用するWindowsのシステム管理用シェルである。シェルであるためコンソールで対話的にコマンドを実行することができるのはもちろん、スクリプトファイル(*.ps1)を記述しバッチ的に実行することも可能である。ここではPowerShellスクリプトで(コンソールでも使用は可能だが)用いることのできる基礎文法を紹介する。2.0で新たに追加された要素である。表示コンソールに文字列を表示。world"コマンドレット(後述)を使用した場合。world"コマンドレットPowerShellはコマンドレットと呼ばれる100種類以上のコマンドライン・ツール群を単独で、あるいはパイプライン(後述)で連結して使用するのが基本となる。コマンドレットは原則verb-nounという命名規則にしたがっている。パラメータ値」を指定する。Frameworkのオブジェクトが含まれる配列であることが多い。このオブジェクト配列がパイプラインを渡って後続のコマンドレットに入力される。通常の配列に関してもパイプラインを使用可能。コメントマルチラインコメント(★2.0)<#複数行に渡るコメントです#>変数の宣言PowerShellは変数の宣言をしなくても変数を使用可能。以下のようにするとどのような型でも代入可能な変数が作られる。変数の型を指定することは可能。以下のようにするとint型のみ格納可能な変数が作られる。1あるいは、コマンドレットを用いて$aという変数を宣言することもできる。この場合変数の型は指定できない。1文法チェック以下を実行することで未定義の変数を参照するとエラーが出るようになる。-strictスクリプトの実行デフォルトの実行ポリシーではスクリプトの実行は不許可であるため、以下のようにポリシーを変更しておく。RemoteSignedスクリプト/コマンドを実行するにはコマンドラインで次のようにする。Frameworkの数値を表す構造体のインスタンスである。数値には整数、浮動小数点があり、変数に代入した段階で適切な型が設定される。System.Stringクラスのインスタンスである。文字列はシングルクォーテーションかダブルクォーテーションで囲む。ダブルクォーテーションの中では`t(タブ)や`r`n(改行)などの特殊文字が使用でき、変数が展開される。最初に見つかった文字列。添え字の1,2...には()内のサブ式にhitした文字列が格納。System.Arrayクラスのインスタンスである。System.Collections.Hashtableクラスのインスタンスである。スクリプトブロックを条件文に記述できる。PowerShellではPerlの文字列比較演算子のような記述をおこなうが、Perlとは異なり文字列も数値も同じ書式である。0xFF007.サブルーチンPowerShellのサブルーチンには関数とフィルタがある。関数とフィルタは呼び出し行の前で宣言する必要がある。filter構文もfunction構文と並んで独自関数を記述するものだが、filter構文はパイプラインに渡されたオブジェクトをフィルタするのに用いる。注:returnを付けなくても関数内で出力された値はすべて呼び出し元に返却される。返却したくない場合は出力値をを[void]にキャストするか|Out-Nullに渡す。Get-Odd8.テキストファイル入出力コマンドレットで可能。エンコーディングは日本語環境のデフォルトではShift-JIS。コマンドレット出力のテキストファイルへの書き出しに関してはリダイレクトも可能。この場合エンコーディングはUnicode。エンコーディングを指定する場合9.例外PowerShellで例外が発生すると、デフォルトではエラーメッセージを表示し次の行を実行する(シェル変数$ErrorActionPreferenceの設定により挙動の変更可能)。エラーが発生すると$Errorにエラー情報の配列が格納され、$?にFalseが格納される。エラーをトラップするには次の構文を使用する。行継続文字1行にすると長いコードを複数行に書くには行継続文字`を用いる。5ステートメント分割ステートメントを分割するには改行コードもしくは;を使用する。JavaScriptと同様、文末に;はつけてもつけなくてもよい。複数行の文字列を記述する方法。Frameworkに含まれているクラスのプロパティやメソッドを使用できる。基本的に完全修飾名を指定しなければいけないが、"System."は省略可能。intなど型エイリアスがいくつか定義されている。コンストラクタがある場合。-staticキャスト-asを使った場合はキャスト失敗時もエラーにならずNullが格納される。[System.DateTime]ユーザー定義オブジェクトPowerShellにはクラスを定義する構文はないが、空のオブジェクト(PSObject)を生成し、任意のプロパティ(ノートプロパティ)を付加することができる。"Name","名前"$obj.PSObject.Members.Add($property)シェル変数あらかじめ定義されている変数。シェル変数には自動変数(変更不可能)とユーザー定義変数(変更すると挙動を変更することができる)がある。自動変数の例を挙げる。:スクリプトの実行情報。$myInvocation.ScriptNameでスクリプトのフルパス取得(★2.0)。