Powershell:合并两个变量名,用于调用动态命名变量

tp5buhyn  于 2023-05-17  发布在  Shell
关注(0)|答案(1)|浏览(215)

我创建了一个动态变量,如下所示:

$Data = @()
$i = 1
Foreach ($S in $SB) {
     New-variable "JR$i" "content"
     New-variable "SN$i" "content"
     New-variable "T$i" "content"
     New-variable "FN$i" "content"
     $i = $i++
}

我的目标是把它们放在一个psobject中,如下所示:

$Data += new-object psobject -property ([ordered]@{JR = "<tr><td>$JR$i</td>"; SN = "<tr><td>$SN$i</td>"; T = "<tr><td>$T$i</td>"; FN = "<tr><td>$FN$i</td>"})
1tu0hz3e

1tu0hz3e1#

当前代码无法运行的原因

1.增量运算符使用不当

$i = $i++-这不是你想的那样。您可能需要$i++$i += 1
你的代码实际上在做什么是复杂的。增量运算符文档说:
运算符的后缀版本在语句中使用变量的值后递增变量**。
换句话说,你的代码$i = $i++是这样做的:

  • 在右侧,计算表达式$i(= 1)
  • 增量$i$i现在等于2)
  • 将先前计算的表达式值(1)赋给左手变量$i
  • $i现在再次等于1!

你可以自己试试:

$i = 1;
$i = $i++;
$i
# 1

您可以通过使用以下选项之一而不是$i = $i++来解决此问题:

  • $i++;
  • $i += 1;
  • $i = $i + 1;
2.插值问题

New-Variable行中,Powershell正在进行字符串插值以创建一个名为JR$i-> JR1的变量,但在第二个示例中,<td>$JR$i</td>扩展了两个不同的变量-$JR-> $null(因为$JR未定义)和$i-> 1,而不是您可能期望的$JR1-> content
你也可以测试一下:

$i = 1;
New-Variable -Name "JR$i" -Value "content";

$JR1
# content

"<td>$JR$i</td>"
# <td>1</td>

如果在收到错误时启用严格模式,则会更清楚:

Set-StrictMode -Version "Latest";

"<td>$JR$i</td>"
# InvalidOperation: The variable '$JR' cannot be retrieved because it has not been set.

你想要的是"<td>$JR1</td>",但是看起来你需要动态地生成变量名,因为你正在循环$i的多个值,所以你将被困在这样做:

$i = 1;
$jr = (Get-Variable -Name "JR$i").Value;

"<td>$jr</td>"
# "<td>content</td>"

如何修复

1.正确增量

这很简单-只需使用$i++$i += 1即可

2.使用哈希表

更多背景信息,请参阅评论中提到的@iRon的general best-practice advice-我将在下面将其应用于您的特定案例。
而不是创建大量的“动态变量”,只需将值打包到一个哈希表中,使用名称作为键-稍后检索值会更容易...

$SB = @( 1, 2 )
$vars = [ordered] @{};
$i = 1
foreach( $S in $SB )
{
   $vars.Add("JR$i", "content");
   $vars.Add("SN$i", "content");
   $vars.Add("T$i", "content");
   $vars.Add("FN$i", "content");
   $i++
}

$vars
# Name                           Value
# ----                           -----
# JR1                            content
# SN1                            content
# T1                             content
# FN1                            content
# JR2                            content
# SN2                            content
# T2                             content
# FN2                            content

注意-严格来说,我使用的是OrderedDictionary而不是哈希表,这样键就可以按照它们被添加的顺序显示,但除此之外它们基本上是一样的。
然后使用hashtable / ordereddictionary:

$i = 1;
foreach( $S in $SB )
{
    "<tr><td>$($vars["JR$i"])</td>";
    $i++
}
# <tr><td>content</td>
# <tr><td>content</td>

但是,如果你只是想生成pscustomobjects,那么从源数据中更干净的方法可能是这样,完全绕过整个“动态变量”和临时哈希表/ OrderdDictionary:

# generate the source data
$SB = @(
  @{
    "JR_Property" = "jr content 1"
    "SN_Property" = "sn content 1"
    "T_Property"  = "t content 1"
    "FN_Property" = "fn content 1"
  },
  @{
    "JR_Property" = "jr content 2"
    "SN_Property" = "sn content 2"
    "T_Property"  = "t content 2"
    "FN_Property" = "fn content 2"
  }
);

$data = $SB | foreach-object {
    [pscustomobject] @{
        "JR" = "<tr><td>$($_.JR_Property)</td>";
        "SN" = "<tr><td>$($_.SN_Property)</td>";
        "T"  = "<tr><td>$($_.T_Property)</td>";
        "FN" = "<tr><td>$($_.FN_Property)</td>"}
}

$data | format-list *
# JR : <tr><td>jr content 1</td>
# SN : <tr><td>sn content 1</td>
# T  : <tr><td>t content 1</td>
# FN : <tr><td>fn content 1</td>
# 
# JR : <tr><td>jr content 2</td>
# SN : <tr><td>sn content 2</td>
# T  : <tr><td>t content 2</td>
# FN : <tr><td>fn content 2</td>

相关问题