如何在Powershell中分配和引用包含方括号的环境变量 [英] How to assign and reference environment variables containing square brackets in Powershell
问题描述
未指定PSDrive时,将执行以下操作:
When the PSDrive is not specified, the following works:
${[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
以下作品,尽管我很好奇它是否有简短的语法:
The following works, though I am curious if there's short hand syntax for it:
Set-Item -LiteralPath env:${[foo]} -Value "bar"
Get-Item -LiteralPath env:${[foo]} | % {$_.Value}
但是以下方法不起作用:
However the following does not work:
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
推荐答案
从PowerShell Core 6.2.0起编写
原因是PowerShell处理以下内容:
The reason is that PowerShell treats the following:
${<drive>:<name>}
就像您已指定:
Get-Content -Path <drive>:<name> # or, with assignment, Set-Content -Path ...
这种表示法-尽管经常与Env:
驱动器(例如$env:Path
)一起使用-鲜为人知,它是名为 命名空间变量表示法的通用范例 em> ,这在此答案中进行了解释.
This notation - though often used with the Env:
drive (e.g., $env:Path
) - is little-known as a general paradigm named namespace variable notation, which is explained in this answer.
问题是使用-Path
而不是-LiteralPath
,因为-Path
将其参数解释为通配符表达式
The problem is the use of -Path
rather than -LiteralPath
, because -Path
interprets its argument as a wildcard expression.
因此,${env:[foo]}
中的[foo]
-而不是按原样使用-被解释为与单个字符匹配的通配符表达式,该字符是f
或o
([foo]
是一个字符集或范围([...]
),与内部的任何(不同)字符匹配-请参见
Therefore, the [foo]
in ${env:[foo]}
- rather than being used as-is - is interpreted as a wildcard expression that matches a single character that is either f
or o
([foo]
is a character set or range ([...]
) that matches any one of the (distinct) characters inside - see about_Wildcards).
向Set-Content -Path
的逻辑要求基于通配符的路径解析为已有的东西,即使您通常是显式创建环境变量不是必需的;例如${env:NoSuchVarExistsYet} = 'new'
可以正常工作.
On assigning to ${env:[foo]}
, the logic of Set-Content -Path
requires that a wildcard-based path resolve to something existing, even though you're generally not required to explicitly create environment variables; e.g., ${env:NoSuchVarExistsYet} = 'new'
works just fine.
解决方法:
使用 double (!)-`
-通配符元字符转义:
Use double(!)-`
-escaping of the wildcard metacharacters:
# 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``]}
注意:
Escaping shouldn't be required at all, because there is no good reason to treat paths that conceptually identify a given, known item as wildcard expressions - see this GitHub issue.
需要转义 double `
是一个附加的怪癖-参见此GitHub问题.
That double `
-escaping is needed is an added quirk - see this GitHub issue.
另一种解决方法-一种不涉及转义的方法-使用
Set-Content -LiteralPath env:[foo] bar
和Get-Content -LiteralPath env:[foo]
,但这既冗长又缓慢.
Another workaround - one that doesn't involve escaping - is to use
Set-Content -LiteralPath env:[foo] bar
and Get-Content -LiteralPath env:[foo]
, but that is both verbose and slow.
关于您尝试过的其他语法变体:
$env:${[foo]}="bar"
由于您的变量引用不是整体上由{...}
括起来的 (初始的$
除外),因此:
之后的标记仅允许包含以下字符: 不需要转义-并且$
,{
和}
都违反了该规则.
Since your variable reference isn't {...}
-enclosed as a whole (except for the initial $
), the token that follows the :
is only allowed to contain characters that do not require escaping - and $
, {
and }
all violate that rule.
-
{...}
-包围整个路径-${env:[foo]}
-解决了语法问题,但遇到了上面详述的问题.
{...}
-enclosing the entire path -${env:[foo]}
- solves the syntax problem, but runs into the problem detailed above.
Set-Item -LiteralPath env:${[foo]} -Value "bar"
这通常不会起作用,因为字符串扩展是在此处预先应用的-就像您已通过"env:${[foo]}"
一样:引用(常规)名为${[foo]}
的变量被扩展 (用其值替换),并且实际上附加在文字env:
之前,之前将结果传递给Set-Item
.
This does not work in general, because string expansion is applied beforehand here - it is as if you had passed "env:${[foo]}"
: the reference to a (regular) variable named ${[foo]}
is expanded (replaced with its value) and in effect appended to literal env:
, before handing the result to Set-Item
.
如果不存在这样的常规变量,则Set-Item
看到的只是env:
(因为不存在的变量默认为$null
,它在字符串上下文中成为空字符串),这将导致错误由于缺少变量名.
If such a regular variable doesn't exist, what Set-Item
sees is just env:
(because non-existent variables default to $null
, which becomes the empty string in a string context), which causes an error due to the lack of variable name.
相反,以下代码将设置一个名为unrelated
的环境变量:
By contrast, the following would set an environment variable named unrelated
instead:
# 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"
.
The same applies to Get-Item -LiteralPath env:${[foo]}
and
Set-Item -LiteralPath env:${[foo]2} -Value "bar"
.
这篇关于如何在Powershell中分配和引用包含方括号的环境变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!