【问题标题】:How to assign and reference environment variables containing square brackets in Powershell如何在 Powershell 中分配和引用包含方括号的环境变量
【发布时间】:2019-08-16 01:12:11
【问题描述】:

当未指定 PSDrive 时,以下工作:

${[foo]}="bar"
echo ${[foo]}

但以下不起作用

$env:${[foo]}="bar"
At line:1 char:1 
+ $env:${[foo]}="bar"
+ ~~~~~
Variable reference is not valid. ':' was not followed by a valid variable name character. Consider using ${} to delimit the name.
At line:1 char:6
+ $env:${[foo]}="bar"
+      ~~~~~~~~~~~~~~
Unexpected token '${[foo]}="bar"' in expression or statement.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : InvalidVariableReferenceWithDrive
${env:[foo]}="bar"
Cannot find path 'env:[foo]' because it does not exist. 
At line:1 char:1
+ ${env:[foo]}="bar"
+ ~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (env:[foo]:String) [], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound

以下工作,虽然我很好奇它是否有简写语法:

Set-Item -LiteralPath env:${[foo]} -Value "bar"
Get-Item -LiteralPath env:${[foo]} | % {$_.Value}

但是以下方法不起作用:

Set-Item -LiteralPath env:${[foo]2} -Value "bar"
Set-Item : Cannot process argument because the value of argument "name" is null. Change the value of argument "name" to a non-null value.      
At line:1 char:1
+ Set-Item -LiteralPath env:${[foo]2} -Value "bar"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:String) [Set-Item], PSArgumentNullException
    + FullyQualifiedErrorId : SetItemNullName,Microsoft.PowerShell.Commands.SetItemCommand

【问题讨论】:

  • 好问题;顺便说一句:Get-Item -LiteralPath env:${[foo]}Set-Item -LiteralPath env:${[foo]} -Value "bar" 也不起作用,或者至少不会像您期望的那样起作用,因为预先进行了字符串扩展。

标签: powershell syntax namespaces environment-variables


【解决方案1】:

从 PowerShell Core 6.2.0 开始编写

原因是 PowerShell 处理如下:

${<drive>:<name>}

好像你已经指定了:

Get-Content -Path <drive>:<name>  # or, with assignment, Set-Content -Path ...

这种表示法 - 虽然经常与 Env: 驱动器一起使用(例如,$env:Path) - 作为一种名为 命名空间变量表示法通用范式鲜为人知em>,在this answer中有解释。

问题在于使用-Path 而不是-LiteralPath,因为-Path 将其参数解释为通配符表达式 .

因此,${env:[foo]} 中的 [foo] - 而不是按原样使用 - 被解释为匹配 单个 字符的通配符表达式,该字符是 fo[foo] 是一个字符集或范围 ([...]),匹配其中的任何一个(不同)字符 - 请参阅 about_Wildcards)。

分配${env:[foo]}时,Set-Content -Path 的逻辑要求基于通配符的路径解析为现有的东西,即使您通常是不需要显式创建环境变量;例如,${env:NoSuchVarExistsYet} = 'new' 工作正常。


解决方法

使用 double(!)-`-转义通配符元字符

# Namespace variable notation only works with if you
# double(!)-backtick-escape the wildcard metacharacters:

# Assign to / implicitly create env. var '[foo]'
${env:``[foo``]} = 'bar'

# Get its value.
${env:``[foo``]}

注意:

  • 根本不需要转义,因为没有充分的理由将在概念上标识给定的已知项目的路径视为通配符表达式 - 请参阅GitHub issue #9225

  • 需要 double `-escaping 是一个额外的怪癖 - 请参阅 GitHub issue #7999

  • 另一种解决方法 - 不涉及转义 - 是使用
    Set-Content -LiteralPath env:[foo] barGet-Content -LiteralPath env:[foo],但这既冗长又缓慢。


至于你尝试过的其他语法变化

$env:${[foo]}="bar"

因为你的变量引用不是{...}-enclosed 作为一个整体(除了最初的$),: 后面的标记只允许包含以下字符不需要转义 - 并且${} 都违反了该规则。

  • {...}-封闭整个路径-${env:[foo]}-解决了语法问题,但遇到了上面详述的问题。

Set-Item -LiteralPath env:${[foo]} -Value "bar"

一般工作,因为这里预先应用了字符串扩展 - 就好像你已经通过"env:${[foo]}":对a(常规)的引用名为${[foo]} 的变量被扩展(替换为它的值)并且实际上附加到文字env:将结果交给Set-Item

如果这样的正则变量不存在,Set-Item 看到的只是env:(因为不存在的变量默认为$null,在字符串上下文中变成空字符串),从而导致错误由于缺少变量名。

相比之下,下面会设置一个名为 unrelated 的环境变量:

# Create a regular variable literally named '[foo]'.
${[foo]} = 'unrelated'

# !! The following sets env:unrelated, i.e., env. var 'unrelated',
# !! due to the string expansion that is performed on the -LiteralPath
# !! argument up front.
Set-Item -LiteralPath env:${[foo]} bar

$env:unrelated # -> 'bar'

这同样适用于Get-Item -LiteralPath env:${[foo]}
Set-Item -LiteralPath env:${[foo]2} -Value "bar"

【讨论】:

    猜你喜欢
    • 2018-09-02
    • 2011-06-06
    • 2016-03-29
    • 1970-01-01
    • 2014-02-21
    • 2021-01-21
    • 2021-12-01
    • 1970-01-01
    • 2015-03-05
    相关资源
    最近更新 更多