二重引用符で囲まれた文字列でオブジェクトのプロパティをどのように使用できますか?


96

私は次のコードを持っています:

$DatabaseSettings = @();
$NewDatabaseSetting = "" | select DatabaseName, DataFile, LogFile, LiveBackupPath;
$NewDatabaseSetting.DatabaseName = "LiveEmployees_PD";
$NewDatabaseSetting.DataFile = "LiveEmployees_PD_Data";
$NewDatabaseSetting.LogFile = "LiveEmployees_PD_Log";
$NewDatabaseSetting.LiveBackupPath = '\\LiveServer\LiveEmployeesBackups';
$DatabaseSettings += $NewDatabaseSetting;

文字列実行コマンドでプロパティの1つを使用しようとすると:

& "$SQlBackupExePath\SQLBackupC.exe" -I $InstanceName -SQL `
  "RESTORE DATABASE $DatabaseSettings[0].DatabaseName FROM DISK = '$tempPath\$LatestFullBackupFile' WITH NORECOVERY, REPLACE, MOVE '$DataFileName' TO '$DataFilegroupFolder\$DataFileName.mdf', MOVE '$LogFileName' TO '$LogFilegroupFolder\$LogFileName.ldf'"

無効なの値で$DatabaseSettingsはなく、単にの値を使用しようとし$DatabaseSettings[0].DatabaseNameます。
私の回避策は、それを新しい変数にコピーさせることです。

二重引用符で囲まれた文字列でオブジェクトのプロパティに直接アクセスするにはどうすればよいですか?

回答:


163

変数名を二重引用符で囲んだ文字列で囲むと、その変数の値に置き換えられます。

$foo = 2
"$foo"

なる

"2"

一重引用符を使用する必要がない場合:

$foo = 2
'$foo'

ただし、プロパティにアクセスする場合、または二重引用符で囲まれた文字列の変数にインデックスを使用する場合は、その部分式をで囲む必要があります$()

$foo = 1,2,3
"$foo[1]"     # yields "1 2 3[1]"
"$($foo[1])"  # yields "2"

$bar = "abc"
"$bar.Length"    # yields "abc.Length"
"$($bar.Length)" # yields "3"

PowerShellはそれらの場合にのみ変数を展開します。インデックス、プロパティ、完全な計算など、より複雑な式の評価を強制するには、それらを部分式演算子$( )で囲み、内部の式を評価して文字列に埋め込む必要があります。


これは機能しますが、最初に回避しようとしていたので、文字列を連結するだけでよいのではないかと思います
ozzy432836

2
@ ozzy432836もちろんできます。または、フォーマット文字列を使用します。それは通常、それほど重要ではなく、個人的な好みに帰着します。
ジョーイ

15

@Joeyは正解ですが、次のようにして評価を強制する必要がある理由についてもう少し追加します$()

サンプルコードには、PowerShellのメーカーが展開を単なる変数参照に制限し、プロパティへのアクセスもサポートしないことを選択した理由を示すあいまいさが含まれています(余談ですが、文字列の展開はToString()オブジェクトのメソッドを呼び出すことによって行われます。いくつかの「奇妙な」結果を説明できます)。

あなたの例はコマンドラインの最後に含まれています:

...\$LogFileName.ldf

オブジェクトのプロパティがデフォルトで展開されている場合、上記は次のように解決されます

...\

参照されるオブジェクトが以降$LogFileNameというプロパティ持っていないldf$null(または空の文字列)を変数に代入されることになります。


1
いい発見。私は実際には彼の問題が完全にわからなかったが、文字列内からプロパティにアクセスしようとすると、悪臭がした:)
Joey

みんなありがとう!ヨハネス、なぜ文字列内のプロパティへのアクセスが悪臭だと思うのですか?それが行われたことをどのように示唆しますか?
caveman_dick

穴居人:それは潜在的なエラーの原因であると私の目を引いたものでした。あなたは確かにそれを行うことができ、それは奇妙なことではありませんが、$()演算子を省略すると、機能しないため「失敗」と叫びます。したがって、私の答えは、私が目にする可能性のある最初の失敗の原因を使用して、あなたの問題が何であるかについての教育を受けた推測でした。そのように見えて申し訳ありませんが、そのコメントはベストプラクティスなどについて言及していませんでした。
ジョーイ

心配してよかった!;)最初にpowershellを使い始めたとき、文字列内の変数は少し変だと思いましたが、とても便利です。構文のヘルプを探すことができる決定的な場所を見つけることができませんでした。
caveman_dick 09

9

@Joeyには良い答えがあります。String.Formatで同等の.NETルックを使用する別の方法があります。オブジェクトのプロパティにアクセスする場合は、次のようにします。

車についてのこと:

$properties = @{ 'color'='red'; 'type'='sedan'; 'package'='fully loaded'; }

オブジェクトを作成します。

$car = New-Object -typename psobject -Property $properties

文字列を補間します。

"The {0} car is a nice {1} that is {2}" -f $car.color, $car.type, $car.package

出力:

# The red car is a nice sedan that is fully loaded

ええ、それは特に.netコードに慣れている場合はもっと読みやすくなります。ありがとう!:)
caveman_dick

3
最初にフォーマット文字列を使用するときに注意すべき落とし穴があります。つまり、式を括弧で囲む必要があることがよくあります。たとえばwrite-host "foo = {0}" -f $foo、PowerShellはのパラメーター-fとして扱われるため、単に書き込むことはできません。この例では、する必要があります。これはPowerShellの標準的な動作ですが、注目に値します。ForegroundColorwrite-hostwrite-host ( "foo = {0}" -f $foo )
andyb 2016

わかりやすく言うと、上の例は「文字列補間」ではなく、「複合フォーマット」です。Powershellは、C#とVB.NETが主要なプログラミング言語である.NETと密接に結びついているため、「文字列補間」および「補間文字列」という用語(および同様のもの)は、それらに含まれる新しい$で始まる文字列にのみ適用する必要があります。言語(C#6およびVB.NET 14)。これらの文字列では、パラメータ式は数値パラメータ参照の代わりに文字列に直接埋め込まれ、実際の式はの引数になりString.Formatます。
Uber Kluger

@andyb、フォーマット文字列「gotchas」に関して。これが、実際にはモードと引数モードの違いです(about_Parsingを参照)。コマンドはトークンに解析されます(意味のある文字列を形成する文字のグループ)。スペースは、マージされるトークンを分離しますが、それ以外の場合は無視されます。コマンドの最初のトークンが数値、変数、ステートメントキーワード(if、whileなど)、単項演算子、{などである場合、解析モードはExpressionそれ以外Argument(コマンドターミネーターまで)です。
Uber Kluger

8

ドキュメンテーションノート:Get-Help about_Quoting_Rules文字列補間について説明しますが、PSv5以降は詳細ではありません。

補完するために、ジョーイの便利な答えをして実用的な要約のPowerShellのの文字列展開(文字列補間二重引用符で囲まれた文字列("...")二重引用符で囲まれた中に含めて、ここでは、文字列):

  • などの参照のみ$foo$global:foo(または$script:foo、...)と$env:PATHする場合(環境変数)が認識され、直接に埋め込まれ"..."た文字列-つまり、唯一の変数の参照自体は関係なく、以下のものの、展開されています。

    • 文字列内の後続の文字から変数名明確にするために、それを{and}囲みます。例えば、${foo}
      変数名が続いている場合、これは特に重要である:PowerShellはそれ以外の間にすべて検討するよう、$およびスコープ通常、補間させ、指定子を失敗します。たとえば、壊れますが、意図したとおりに機能します。 (または、-をエスケープします:) 。:"$HOME: where the heart is.""${HOME}: where the heart is."
      `:"$HOME`: where the heart is."

    • a $またはa "リテラルとして扱うには、その前にエスケープ文字を付けます。`バックティック); 例えば:
      "`$HOME's value: `"$HOME`""

  • 配列添え字の使用やオブジェクト変数のプロパティへのアクセスなど、その他の場合は、式を部分式演算子(例:または)で囲む$(...)必要があります。"PS version: $($PSVersionTable.PSVersion)""1st el.: $($someArray[0])"

    • 使い方は$(...)も、あなたは、二重引用符で囲まれた文字列(例えば、全体のコマンドラインからの出力を埋め込むことができます"Today is $((Get-Date).ToString('d')).")。
  • 補間結果は、必ずしもデフォルトの出力フォーマットと同じであるとは限りません(たとえば、変数/部分式をコンソールに直接出力した場合に表示されるもの、たとえば、デフォルトのフォーマッターが関係する場合Get-Help about_format.ps1xml)。

    • コレクションアレイを含むが、により文字列に変換され配置単一の空間を要素の文字列表現の間(デフォルトでは、異なるセパレータを設定することによって指定することができる$OFS)、例えば、"array: $(@(1, 2, 3))"収率array: 1 2 3

    • インスタンス任意の他のタイプ(コレクション自体ではないコレクションの要素を含む)されることによって文字列化のいずれかを呼び出すIFormattable.ToString()と方法を不変培養インスタンスのタイプがサポートされている場合、IFormattableインターフェースを[1] または呼び出すことによって.psobject.ToString()、ほとんどの場合、単に呼び出します基になる.NET型の.ToString()メソッド[2]。意味のある表現を提供する場合としない場合があります。(非プリミティブ)型が.ToString()メソッドを明示的にオーバーライドしていない限り、取得できるのは完全な型名(例:"hashtable: $(@{ key = 'value' })"yields hashtable: System.Collections.Hashtable)だけです。

    • コンソールと同じ出力取得するには、必要に応じて、部分式とパイプをOut-String使用して、.Trim()先頭と末尾の空行を削除て適用します。たとえば、
      "hashtable:`n$((@{ key = 'value' } | Out-String).Trim())"利回り:

      hashtable:                                                                                                                                                                          
      Name                           Value                                                                                                                                               
      ----                           -----                                                                                                                                               
      key                            value      

[1]これはおそらく驚くべき動作であり、文化に敏感な表現をサポートする型の場合$obj.ToString()現在の文化に適した表現が生成されますが、"$obj"(文字列補間)は常に文化に不変の表現になります- 私のこの回答を参照してください。

[2]重要なオーバーライド:
*以前に説明したコレクションの文字列化(などの要素ではなく、スペースで区切られた要素のリストSystem.Object[])。
* 空の文字列ではなく、ハッシュテーブルのよう[pscustomobject]インスタンスの表現(ここで説明)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.