简体   繁体   English

PowerShell:在字符串中使用未声明的变量

[英]PowerShell: Use undeclared variable in string

I'm trying to figure out how I can use undeclared variables in a string.我试图弄清楚如何在字符串中使用未声明的变量。 This is a simplified example to demonstrate my issue这是一个演示我的问题的简化示例

[string]$sentence="My dog is $age years old"
[int]$age = 6 
$sentence | write-output

$age = 3
$sentence | write-output

Looking for this output:寻找这个 output:

   My dog is 6 years old

   My dog is 3 years old

Getting this output:获取此 output:

   My dog is  years old

   My dog is  years old

I've tried the following:我试过以下方法:

  "My dog is `$age years old" #My dog is $age years old
  $("My dog is `$age years old") #My dog is $age years old
  $("My dog is $age years old") #My dog is 3 years old

Is it possible in any way to make this more compact?有没有可能以任何方式使它更紧凑? or is this the only way?还是这是唯一的方法?


edit: I noticed the focus is on strings.编辑:我注意到重点是字符串。 I will share my code where this was an issue.我将在出现问题的地方分享我的代码。 I need to migrate a bunch of VBS-scripts (>40) varying from 20 lines to 2000 lines to Powershell我需要迁移一堆 VBS 脚本(> 40)从 20 行到 2000 行到 Powershell

VBS-file: VBS 文件:

    Function InitializeApp

        Dim sPath
        
        ...

    End function 

Powershell Script: Powershell 脚本:

$vbs=Get-Content -path $path #get content in array, one line per index
$rules=
@(
    [pscustomobject]@{
        "name"="func_start";
        "vbs" = 'Function (?<V1>\w*)'; # The regex named group V1 will initialized when match is found
        "ps" = {"Function $1() `{`n"} # Group V1 is to be inserted in replacement string
    }
)

function Invoke-TestAndReplace($line,$ruleName){
    $r_vbs=$($rules.where({$_.name -eq $ruleName}).vbs) # Function (?<V1>\w*)
    $r_ps=$($rules.where({$_.name -eq $ruleName}).ps) # {"Function $1() `{`n"}
    if( $regex = ($line | select-string -pattern $r_vbs )) {
        $0=$regex[0].Matches.Groups.Where({$_.name -eq "0"}).value # Function InitializeApp
        $1=$regex[0].Matches.Groups.Where({$_.name -eq "V1"}).value # InitializeApp
        $2=$regex[0].Matches.Groups.Where({$_.name -eq "V2"}).value #
        $r_ps = & $r_ps # Function InitializeApp() {
        $replace = $line.replace($0,$r_ps) # Function InitializeApp -> Function InitializeApp() {
    } else {$replace = $line} #keep old value
    return $replace
}
$newVBS=@()
foreach($line in $vbs){
    $line = Invoke-TestAndReplace -line $line -rulename "func_start"
}

I don't know how to do this with interpolation, but I can do it with the older.Net String.Format() method like this:我不知道如何使用插值来做到这一点,但我可以使用 older.Net String.Format()方法来做到这一点,如下所示:

$sentence = "My dog is {0} years old."

$age = 6
[string]::Format($sentence, $age) | Write-Output
# => My dog is 6 years old

$age = 3
[string]::Format($sentence, $age) | Write-Output
# => My dog is 3 years old

[string]::Format($sentence, 12)   | Write-Output
# => My dog is 12 years old

Which we can shorten like this (thank you commenters):我们可以这样缩短(感谢评论者):

$sentence = "My dog is {0} years old."

$age = 6
Write-Output ($sentence -f $age)
# => My dog is 6 years old

$age = 3
Write-Output ($sentence -f $age)
# => My dog is 3 years old

Write-Output ($sentence -f 12)
# => My dog is 12 years old

Also note the different placeholder in the template string.还要注意模板字符串中的不同占位符。

This answer shows an overcomplicated alternative to the nice answer from Joel Coehoorn .这个答案显示了一个过于复杂的替代方案,而不是 Joel Coehoorn 的好答案 You can use a Script Block , to store an expression (including your $age variable) and then execute it.您可以使用Script Block来存储表达式(包括您的$age变量)然后执行它。

$sentence = { "My dog is $age years old" }
$age = 6 
& $sentence | write-output # => My dog is 6 years old

$age = 3
& $sentence | write-output # => My dog is 3 years old

If you want your script block to "remember" the value of a variable at the moment it was created you can use it's .GetNewClosure() method , for example:如果您希望您的脚本块在创建变量时“记住”变量的值,您可以使用它的.GetNewClosure()方法,例如:

$expressions = foreach($i in 0..5) {
    { "Value of `$i was $i in this iteration" }.GetNewClosure()
}
$expressions.foreach{ & $_ }

You can use ExpandString您可以使用扩展字符串

$sentence = 'My dog is $age years old.'

$age = 4
$ExecutionContext.InvokeCommand.ExpandString($sentence)
# My dog is 4 years old.

$age = 5
$ExecutionContext.InvokeCommand.ExpandString($sentence)
# My dog is 5 years old.

You could also define a function and call the function您还可以定义一个 function 并调用 function

function sentence([int]$age) {
    "My dog is $age years old"
}

1..5 | ForEach-Object { sentence -age $_ }

# My dog is 1 years old
# My dog is 2 years old
# My dog is 3 years old
# My dog is 4 years old
# My dog is 5 years old

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM