Powershell 7:在字符串文字中使用与号 (&)

问题描述 投票:0回答:3

我正在尝试在 PowerShell 中执行以下命令,但我不知道如何转义作为 URL 一部分的 & 字符

  az rest `
    --method GET `
    --uri ("https://graph.microsoft.com/v1.0/groups?`$count=true&`$filter=startsWith(displayName,'some+filter+text')&`$select=id,displayName") `
    --headers 'Content-Type=application/json'

由于 & 字符用于启动新命令,因此它会破坏 url 并想要执行其余部分。

有没有办法告诉 powershell 不要这样做?

powershell
3个回答
12
投票

Olaf的回答提供了有效的解决方案;让我添加一个解释:

问题的根源是两种行为的汇合:

  • 调用外部程序时,PowerShell 仅根据给定参数值包含空格对每个参数执行按需双引号 - 否则,参数将被传递不加引号 - 无论是否包含空格该值是最初PowerShell命令中引用的(例如,

    cmd /c echo ab
    cmd /c echo 'ab'
    cmd /c echo "ab"
    都会导致 unquoted
    ab
    作为命令行上的最后一个标记传递(PowerShell 在幕后重建以最终用于执行)。

  • Azure

    az
    CLI 作为批处理文件实现 (
    az.cmd
    ),当调用批处理文件时,
    cmd.exe
    会解析给定的参数;令人惊讶的是 - 并且可以说是不恰当的 - 它解析它们就好像命令是从
    cmd.exe
    会话内部提交的

因此,如果参数从 PowerShell 传递到批处理文件,且 (a) 不包含空格,但 (b) 包含

cmd.exe
元字符,例如
&
,则调用 会中断

一个简单的演示,使用

cmd /c echo
调用作为对批处理文件的调用的替代:

# !! Breaks, because PowerShell (justifiably) passes *unquoted* a&b
# !! when it rebuilds the command line to invoke behind the scenes.
PS> cmd /c echo 'a&b'
a
'b' is not recognized as an internal or external command,
operable program or batch file.

共有三种解决方法

  • 使用嵌入
    "..."
    引用:
# OK, but with a CAVEAT: 
#   Works as of PowerShell 7.2, but arguably *shouldn't*, because
#   PowerShell should automatically *escape* the embedded " chars. as ""
PS> cmd /c echo '"a&b"'
"a&b"

# Ditto, using an *expandable* (interpolating) PowerShell string:
PS> cmd /c echo "`"$HOME & Family; can't put a `$ value on that.`""
"C:\Users\jdoe & Family; can't put a $ value on that." # e.g. 
# OK, but with a CAVEAT:
#  Requires "..." quoting, but doesn't recognize *PowerShell* variables,
#  also doesn't support single-quoting and line continuation.
PS> cmd /c echo --% "a&b"
 "a&b"
  • 通过
    cmd /c
    调用并传递包含批处理文件调用及其所有参数的 single 字符串,(最终)使用
    cmd.exe
    的语法
# OK (remember, cmd /c echo stands for a call to a batch file, such as az.cmd)
# Inside the single string passed to the outer cmd /c call,
# be sure to use "...", as that is the only quoting cmd.exe understands.
PS> cmd /c 'cmd /c echo "a&b"'
"a&b"

# Ditto, using an *expandable* (interpolating) PowerShell string:
PS> cmd /c "cmd /c echo `"$HOME & Family; can't put a `$ value on that.`""
"C:\Users\jdoe & Family; can't put a $ value on that." # e.g. 

退一步

现在,如果您不必担心所有这些事情,那不是很好吗? 特别是因为您可能不知道或不关心给定的 CLI - 例如

az
- 是否会 发生 实现 作为批处理文件

作为 shell,PowerShell 应尽最大努力在幕后忠实地传递参数,并允许调用者专门专注于仅满足 PowerShell 的语法规则:

  • 不幸的是,PowerShell 迄今为止(PowerShell 7.2)通常在这方面做得非常差,无论

    cmd.exe
    有什么怪癖 - 请参阅这个答案了解总结。

  • 关于

    cmd.exe
    的(批处理文件调用)怪癖,PowerShell 可以在未来版本中可以预见地弥补它们 - 但不幸的是,这似乎不会发生;请参阅 GitHub 问题 #15143


1
投票

我现在无法访问 Azure 租户进行测试,实际上我一般没有使用 Azure CLI 的经验,但我希望它能正常工作:

az rest `
    --method GET `
    --uri 'https://graph.microsoft.com/v1.0/groups?$count=true&$filter=startsWith(displayName,some+filter+text)&$select=id,displayName' `
    --headers 'Content-Type=application/json'

或者这个:

az rest --method GET --headers "Content-Type=application/json" `
    --% --uri "https://graph.microsoft.com/v1.0/groups?$count=true&$filter=startsWith(displayName,some+filter+text)&$select=id,displayName"

我添加反引号只是为了提高可读性 - 您可以在实际代码中删除它们。


0
投票

虽然 Olaf 的解决方案和 mklement0 的解决方法有效,但还有一些替代解决方案选项,请参阅 Microsoft 的示例。好处是,如果您有一个包含&符号的变量,它们也可以工作。

https://learn.microsoft.com/en-us/cli/azure/use-azure-cli-successively-powershell?tabs=read%2CBash1%2CBash2#pass-parameters-containing-the-ampersand-symbol

# When quoted by single quotes ('), double quotes (") are preserved by PowerShell and sent
# to Command Prompt, so that ampersand (&) is treated as a literal character
> az '"a&b"' --debug
Command arguments: ['a&b', '--debug']

# Escape double quotes (") with backticks (`) as required by PowerShell
> az "`"a&b`"" --debug
Command arguments: ['a&b', '--debug']

# Escape double quotes (") by repeating them
> az """a&b""" --debug
Command arguments: ['a&b', '--debug']

# With a whitespace in the argument, double quotes (") are preserved by PowerShell and
# sent to Command Prompt
> az "a&b " --debug
Command arguments: ['a&b ', '--debug']

# Use --% to stop PowerShell from parsing the argument
> az --% "a&b" --debug
Command arguments: ['a&b', '--debug']

以变量为例:

$ihaveweirdchars="A@J7aa6bkK&mtKK&53F9`$jC0P`$0Khi"
az "`"$ihaveweirdchars`"" --debug
Command arguments: ['A@J7aa6bkK&mtKK&53F9$jC0P$0Khi', '--debug']
© www.soinside.com 2019 - 2024. All rights reserved.