2016-04-21 24 views
2

に$ argsを使用[OK]を、私は別のにかなり長い間コード化されてきたが、私は、関数の戻りのPowershellsの概念を得ていないのです....PowerShellの:関数から予期しない戻り値、アクセスパラメータ

?私はPowershellにとって非常に新しいので、私は何か非常に基本的なものが欠けていると確信しています。

私は、以下の機能を持っている:

function plGetKeyValue ([string] $FileName, [string] $SectionName, [string] $Key) 
{ 
    if ($PSBoundParameters.Count -lt 2 -or $PSBoundParameters.Count -gt 3 ) 
    { 
     "Invalid call to {0} in {1}" -f $MyInvocation.MyCommand.Name, 
             $MyInvocation.MyCommand.ModuleName 
     return 
    } 

    # Declaration 
    $lFileContents = "" 
    $lSections  = "" 
    $lDataStart  = "" 
    $lStart   = -1 
    $lEnd   = -1 
    $lFoundSection = "" 
    $lNextSection = "" 
    $lResults  = "" 
    $lRetValue  = "" 

    # Handle the optional parameter. 
    if ($PSBoundParameters.Count -eq 2 ) { 
     $PSBoundParameters.Add('Key', $SectionName) 
     $PSBoundParameters.Remove('SectionName')   
     $Key = $SectionName 
     $SectionName = $null 
    } 


    # Read the file in 
    $lFileContents = Get-Content $FileName | Select-String -Pattern .* 

    # Get the sections. 
    $lSections = $lFileContents -match '\[' 
    $lSections = $lSections -notmatch '#' 

    # Start of the data. 
    $lDataStart = $lFileContents | Select-String -Pattern "^#", "^$" -NotMatch ` 
           | select-object -First 1 

    # We have a section. 
    if ($PSBoundParameters.ContainsKey('SectionName')) { 

     # Find the section. 
     $lFoundSection = $lSections | Select-String -Pattern "$lSectionName\b" 

     # If none found we are out. 
     if (-Not $lFoundSection) { return $lRetValue } 

     # Starting point for the key search is the line following 
     # the found section. 
     $lStart = $lFoundSection[0].LineNumber 

     # Loop through the sections and find the one after the found one. 
     $lNextSection = $lSections | ForEach-Object { 
      # If we hit it, break. 
      if ($_.LineNumber -gt $lStart) { 
       break; 
      } 
     } 

     # Set the ending line for the search to the end of the section 
     # or end of file. Which ever we have. 
     if ($lNextSection) { 
      $lEnd = $lNextSection[0].LineNumber 
     } else { 
      $lEnd = $lFileContents[-1] 
     } 
    } else { 
    # No section. 
     $lStart = $lDataStart.LineNumber 

     # Set the ending line for the search to the end of the section 
     # or end of file. Which ever we have. 
     if ($lSections) { 
      $lEnd = $lSections[0].LineNumber 
     } else { 
      $lEnd = $lFileContents[-1] 
     } 
    } 

    # Extract the lines starting with the key. 
    $lResults = $lFileContents[$lStart..$lEnd] -match "$Key\b"  
    # We got results. 

    # Split the value off. 
    return $lRetValue = $lResults[0] | Select -ExpandProperty "Line" 
} 
私が研究し

1)ドキュメントと混乱しているいくつかの質問を巻き起こしたこの機能を作成するプロセスは、$ argsを使用する必要があることを示し

議論を決定する。それは私のために設定されていないようですか?私はバージョン4を使用していますか?代わりに私は$ PSBoundParametersを使用しました。これはお勧めですか?

2)多くの読み取りとヘッドのスクラッチに基づいて、私は関数からの戻り値がすべての未キャプチャ出力をパイプラインに返すことを発見しました。誰かが、キャプチャされていない明確にしてくださいできますか?

例として、変数$ lRetValueに文字列を返す関数を以下に示します。現在、Trueを返しています。それに基づいて私は何かが捕らえられていないと信じていますか?しかし、私が実行しているものはすべて変数に取り込まれます。私は何が欠けていますか?

$FileName = "S:\PS\Home\GlobalConfig\jobs.cfg" 
$key = "Help" 
$section = "Section" 

$r = plGetKeyValue $FileName $Key 
write-host "r is: $r" 

出力が示す次のように:

PS C:

呼び出すルーチンは、次の形式のコードを呼び出している> S:\ PS \ホーム\仕事\ Test.ps1 をrは:True

ご援助をいただければ幸いです。

+0

1) '$のargs' *決して*を移入? 'function test {echo $ args};を実行するとどうなりますか?テスト "asdf" '?それは "asdf"をエコーし​​ませんか? – TessellatingHeckler

+2

2) '$ files = Get-ChildItem'は変数内のGet-ChildItemの戻り値を取得します。あなたがそれをしないと、 'Get-ChildItem'出力はパイプラインに行きます。それが関数内で発生すると、関数はパイプライン内の他のものと共に関数の戻り値の一部になります。 'return'キーワードは、特定の値を返す際の他の言語と同じものではありません。 – TessellatingHeckler

+0

さらにargsを試して、何が起こるかを見てみましょう。私はそれがどのように働いたかについて、私はちょうど純粋に間違っていたと思った。しかし、助けてくれてありがとう。 –

答えて

4

用語注:やや恣意、私はパラメータ以下引数を区別します:
- パラメータ関数宣言の一部として定義されているプレースホルダとして
- など指定された呼び出しのプレースホルダにバインドされたの値の値とは異なります。

概念情報:

1)ドキュメントには、$ argsを引数を決定するために使用されるべきであることを示しています。

$args非高度(非レット)関数で未結合引数を調べるため代替機構です。

$argsが移入さ:

  • 関数がないは(関数がparam(...)パラメータ宣言文の存在によって高度な機能としてマークされている機能を進んでいる場合にのみ - とは対照的にパラメータで飾られている場合)の中でパラメータを宣言することになります)。

  • でも、それはの非公開引数(宣言されたパラメータにマップされていない)のみを含んでいます。

    つまり

に:あなたはすべてのパラメータを指定せずに、あなたの関数を宣言した場合にのみ$argsが渡さすべての引数が含まれていません。

逆に、高機能でありがない未結合引数でなければならず、パラメータにバインドすることができない引数で高度な機能を呼び出す単にが失敗は(エラーが発生します)。

の拡張機能は、PowerShellインフラストラクチャ全体と最もよく統合されているため、一般的にはお勧めできます。$argsを使用せずに行うのが最善です。
有効な入力引数シナリオをすべて網羅するには、複数のparameter setsおよび/または配列パラメータの組み合わせを使用します。

$PSBoundArguments宣言パラメータにバインドされた引数を含み、パラメータ名(例えば、$SectionName)に対応する変数名を直接使用することができるので、必要に応じて通常ないあります。 (スプラット@PSBoundArgumentsを介して、バインドされたすべてのパラメータを別のコマンドレット/関数に渡すなど、特殊な用途があります)。

2)多くの読み込みと頭のスクラッチに基づいて、私は関数からの戻り値がすべての未キャプチャ出力をパイプラインに返すことを発見しました。誰かが、 "uncaptured"を明確にしてくださいできますか?出力はに割り当てることによって、例えば(をキャプチャされない限り、一般的には、出力を生成する任意のPowerShellの文または式が、デフォルトで(Unixシェルでstdoutに緩く同等の)成功ストリームに送信され

変数)またはがリダイレクト(たとえば、出力をファイルに送信することによって)。

このように、ほとんどのプログラミング言語がどのように振る舞うかを逆にするには、文を出力しないようにする必要があります。

あなたは文の出力に興味がない場合は(/キャプチャ後で使用するためにそれをリダイレクトではなく)、あなたはOut-Nullをコマンドレットに$null/dev/nullに相当)、パイプにリダイレクトする、あるいはダミーために割り当てることができます変数$null$null = ...)。

したがって、話すの方法で、あなたはが成功ストリーム捕捉されていないに送信されることを出力を呼び出すことができます。

しかしreturn書に無関係で、:

return文がない仕事他の言語と同じように行います。 PowerShellの主な目的は制御フローメカニズムで、の出力でものデータを出力することができます(引数を指定すると、関数またはスクリプトブロックを終了することができます)。 別の出力を成功ストリームに送信する方法)。

あなたの特定の問題を診断する

あり、あなたの関数が良くPowerShellの市民作ることができる多くの方法は、[1] ですが、あなたの即時問題はこれです:

$PSBoundParameters.Remove('SectionName') 

は、ブール値を返します。出力ストリームに送信されたである3210は、それを抑止、キャプチャもリダイレクトもしていないためです。あなたの場合、$SectionNameパラメータにバインドされているため、$PSBoundParametersにエントリがあるので、$PSBoundParameters.Remove('SectionName')$trueを返します。

このようなものを使用し、この不要な出力を抑制するために:

$null = $PSBoundParameters.Remove('SectionName') 

一般的にあなたが文は出力を生成しないことをを知っない限り、それは安全であると$null =を付加する方が良いでしょう(または使用して、話します出力を抑制する同等のメカニズム)。

特にのメソッドでオブジェクトを呼び出すと、出力になる値(成功ストリームに送信されます)が返されるかどうかは不明です。


[1]次のヘルプトピックには、さらに情報を提供しています。
- パラメータ、help -Full/-Detailed ...でそれらを検査する方法などの使用:
help about_Parameters
- シンプル関数とそのパラメータの定義:
help about_functions
アドバンスの機能に進むことができます。
help about_functions_advanced
とそのパラメータの定義:
help about_Functions_Advanced_Parameters

+1

* "' $ PSBoundParameters.Remove( 'SectionName') 'はブール値を返します" * - Ohhh! – TessellatingHeckler

+1

情報と明確な説明に感謝します。私は返されている削除操作からブール値を考えなかったでしょう!私はPowershellでもっと仕事をして、たくさんの実験をする必要があると思います。 –

+0

@PaulLeDuc:私の喜び。 PowerShellは習得するのに時間がかかりますが、消費する価値のある時間です。その一貫性、包括的なヘルプシステムとイントロスペクションメソッドは、特に実験を通して、学習を容易にします。 – mklement0

関連する問題