Powershell:将 json 字符串传递给 curl

Powershell: passing json string to curl

提问人:KoenJ 提问时间:7/15/2014 最后编辑:mklement0KoenJ 更新时间:7/28/2023 访问量:19475

问:

我正在尝试使用 curl 将 JSON 字符串从 powershell 脚本中传递到 build.phonegap.com api。
根据 phonegap 的论坛,在 Windows 机器上运行时,JSON 数据必须格式化为:

curl.exe -ku user@email:mypass -X PUT -d "data={\"password\":\"keypass\"}" https://build.phonegap.com/api/v1/key

事实上,当从命令行调用时,它确实运行良好。
但是,当我尝试从 powershell 脚本中调用它时,双引号似乎被剥离了。

到目前为止,我已经尝试过:

  • 将 JSON 放在单引号字符串中:
curl.exe -ku user@email:mypass -X PUT -d '"data={\"password\":\"keypass\"}"'  https://build.phonegap.com/api/v1/key
  • 将 JSON 放在单引号字符串中,不带 DOS 转义反斜杠:
curl.exe -ku user@email:mypass -X PUT -d '"data={"password":"keypass"}"'  https://build.phonegap.com/api/v1/key
  • 将 JSON 放在单引号字符串中,转义双引号和反斜杠(带有反斜杠的 DOS 样式):
curl.exe -ku user@email:mypass -X PUT -d '\"data={\\\"password\\\":\\\"keypass\\\"}\"'  https://build.phonegap.com/api/v1/key
  • 将 JSON 放在双引号字符串中,并使用 powershell 反引号字符 () 转义双引号:`
curl.exe -ku user@email:mypass -X PUT -d "`"data={\`"password\`":\`"build*2014`\`"}`""  https://build.phonegap.com/api/v1/key

知道如何实现这一目标吗?

感谢您抽出时间接受采访, 科恩

PowerShell 卷曲 转义 引号

评论

1赞 njzk2 7/15/2014
the double quotes seem to be stripped.你怎么断言?
0赞 KoenJ 7/15/2014
我创建了一个虚拟的控制台应用程序,它只是回显传入的参数。
0赞 mklement0 5/13/2021
重新审视您的其他解决方案尝试:最后一个应该实际有效,尽管内部封闭不是必需的,并且虽然附加 -escaping 的解决方法是有效的,但它 (a) 不应该是必需的,并且 (b) 如果基础 PowerShell 问题得到解决,则会中断,尽管这可能会通过修复来缓解 - 目前(自 PowerShell Core 7.2.0-preview.5 起)仅作为实验性功能提供 PSNativeCommandArgumentPassing可能需要选择加入 - 假设它成为官方功能。"\
0赞 meJustAndrew 8/6/2021
如果要使用文件中的有效负载数据,请参阅此答案

答:

-1赞 David Pullar 7/15/2014 #1

设置内容类型:

curl -H "Content-Type: application/json" -d '{"password":"keypass"}' https://build.phonegap.com/api/v1/key

评论

2赞 KoenJ 7/15/2014
这没有任何区别..请注意,从命令行调用该命令时工作正常,因此问题不在于传递的参数;它与 Powershell 和转义字符有关。
3赞 MortenB 3/13/2020
如果你在powershell中调用它,它是的别名,这不是你想要的,你应该使用。您可以看到所有带有 的别名。curlInvoke-WebRequestcurl.exeGet-Alias
0赞 mklement0 3/30/2021
好点子,@MortenB - 这绝对是 Windows PowerShell(PowerShell 版本高达 v5.1)的要求。相比之下,它不再是 PowerShell 跨平台版本 PowerShell (Core) 7+ 中的内置别名,而是在其中调用。curlcurl.exe
21赞 Keith Hill 7/15/2014 #2

尝试使用运算符将 PowerShell 置于简单(哑)参数分析模式:--%

curl.exe --% -ku user@email:mypass -X PUT -d "data={\"password\":\"keypass\"}" https://build.phonegap.com/api/v1/key

这对于使用与 PowerShell 的参数语法相冲突的参数语法调用 exe 通常很有用。这确实需要 PowerShell V3 或更高版本。

评论

1赞 Keith Hill 7/16/2014
几年前,我还写了一篇关于此功能的博客文章 rkeithhill.wordpress.com/2012/01/02/......
0赞 mklement0 3/30/2021
@StevenPenny,答案中有一个错别字(已更正);除此之外,它仍然有效,但使用 停止解析符号是有代价的,如前面的评论中所述。--%
0赞 Zombo 3/30/2021
@mklement0甚至纠正了运算符毫无意义,因为它仍然随机去掉双引号,并造成糟糕的 shell 体验--%
0赞 mklement0 3/30/2021
@StevenPenny 是的,它带来了糟糕的 shell 体验,现在已经提供了大量关于原因和方式的指示。不,它不会随机去掉双引号。
1赞 Arindam Roychowdhury 2/18/2022
更新:这在 Powershell 7.2 上也运行良好
13赞 mklement0 3/28/2021 #3

更新

  • PowerShell 7.3.0 主要解决了这个问题,但在 Windows 上有选择性的例外 - 有关详细信息,请参阅此答案

  • 对于跨版本、跨版本代码,下面讨论的模块可能仍然值得关注。Native

tl;博士

不幸的是,在 Windows PowerShellPowerShell (Core) v7.2.x 及之前的版本中,必须手动 \-转义传递给外部程序的参数中嵌入的“字符。

# From inside PowerShell:
# Note the outer '...' quoting and the unexpected need to escape
# the embedded " chars. as \" (unexpected, because PowerShell itself doesn't
# require " inside '...' to be escaped; also, PowerShell's escape char. is `).
# If outer "..." quoting must be used, use \`" (sic) to escape the embeded "
curl.exe -ku user@email:mypass -X PUT -d 'data={\"password\":\"keypass\"}' https://build.phonegap.com/api/v1/key

请继续阅读,了解为什么这是必要的。


  • PowerShell 的转义字符 '(所谓的反引号),因此为了在(双引号值)字符串中嵌入字符,请使用 '“(或 )而不是 ;相比之下,在(单引号,逐字)字符串中,不需要转义。""..."""\"'...'"

    • 在您的尝试中,PowerShell 没有看到转义,因此看到了多个字符串,最终 - 当 PowerShell 在幕后应用其按需重新引用时,传递了两个单独的字符串参数,这些参数由于不包含空格,因此不需要双引号,即:逐字逐句和\"""..."data={\password\:\keypass\}

    • 使用 PowerShell 的引用规则,你应该使用

      • 也:

        • "data={`"password`":`"keypass`"}"
      • 或者,更简单地说,假设不需要字符串插值,通过一个逐字引号字符串,其中的字符。 不需要转义:"

        • 'data={"password":"keypass"}'
      • 然而,不幸的是,直到 PowerShell 7.2.x 这还不够;请继续阅读了解详情。

  • 在 PowerShell 7.2.x 之前,在调用(大多数)外部程序时,需要对嵌入的“字符进行意外的额外转义层

    • Windows PowerShell 中,在一些极端情况下,此方法不起作用,在这种情况下,需要使用 (见下文)。值得注意的是,由于括号位于字符串的开头和结尾,因此转义是行不通的 - 有关详细信息,请参阅此答案--%'"foo bar"''\"foo bar\"'\"

    • 此外,Windows 上的某些外部程序仅理解 -escaping(例如);对于它们,use in 以便以编程方式执行额外的转义,假设该值至少包含一个空格。对根本不支持嵌入式字符的程序 (WSH) 执行相同的操作,以便嵌入的至少不会破坏参数边界(但它们将被剥离)。""msiexec-replace '"', '""'""

    • 对于期望 \“-转义的程序,请使用以下操作以编程方式可靠地执行额外的转义-replace

      • '...' -replace '(\\*)"', '$1$1\"'
      • 如果输入字符串不包含预先存在的逐字序列,则可以简化为\"'...' -replace '"', '\"'
# Note: Escaping the embedded " chars. as `" is enough for PowerShell itself,
#       but, unfortunately, not when calling *external programs*.
#       The `-replace` operation performs the necessary additional \-escaping.
$passwd = 'foo'
curl.exe -ku user@email:mypass -X PUT -d (
  "data={`"password`": `"$passwd`"}" -replace '(\\*)"', '$1$1\"'
) https://build.phonegap.com/api/v1/key
  • 这不应该是必需的,但这是由于自 v1 以来的一个错误,由于担心破坏向后兼容性而尚未修复 - 请参阅此答案

  • PowerShell v7.3 主要解决了这个问题,但在 Windows 上有选择性的例外

    • 选择性异常 - 请参阅$PSNativeCommandArgumentPassing首选项变量的描述 - 是不幸的,因为它们保留了异常列表中程序的旧损坏行为,特别是 WSH(Windows 脚本主机)可执行文件及其关联的脚本文件 (, , , , ),并有可能将来零碎地添加到异常列表中 - 请参阅 GitHub 问题 #18660 中的此摘要cmd.exe.cmd.bat.js.vbs.wsf

    • 可悲的是,通过对 Windows 上备受瞩目的 CLI 进行幕后调整,避免了这些异常需求的机会被错过了;请参阅 GitHub 问题 #15143 中的此摘要。

  • 向后和向前兼容的帮助程序函数Native 模块 () 中的 ie 函数,它消除了额外转义的需要,包含 Windows 上高配置 CLI 的重要调整,并且即使修复到位,也将继续按预期工作:Install-Module Native
    ie curl.exe ... -d "data={`"password`": `"$passwd`"}" ... )

  • 使用 --%停止解析符号,如 Keith Hill 的答案所示,是一种次优的解决方法也不需要额外的 -转义,但是\

    • --%具有固有的局限性 - 请参阅 GitHub 文档问题 #6149 - 并且在类 Unix 平台上几乎毫无用处 - 请参阅 GitHub 文档问题 #4963
    • 在以下参数中嵌入 PowerShell 变量值的唯一笨拙且产生副作用的方法是 (a) 将它们定义为环境变量(例如 ),并且 (b) 引用这些变量 cmd.exe 样式,即使在 Unix 上也是如此(例如,)。--%$env:passwd = 'foo'%passwd%
  • 另一种解决方法(尤其是需要在调用中包含 PowerShell 变量或表达式的值)是通过 cmd /c 使用包含整个命令行的单个参数进行调用;为方便起见,以下示例使用 here-string(有关 PowerShell 字符串文本的概述,请参阅此答案的底部部分):

# Use @"<newline>...<newline>"@ if you need to embed PowerShell variables / expressions.
cmd /c @'
curl.exe -ku user@email:mypass -X PUT -d "data={\"password\":"\keypass\"}" https://build.phonegap.com/api/v1/key
'@

评论

1赞 Zombo 3/28/2021
感谢您的详细回答,但坦率地说,这些都不是可以接受的解决方案。我想运行这样的命令:没有所有额外的转义。由于我使用的是单引号,因此它应该有效。使用 Bash,可以使用单引号而不是转义。PowerShell 无法做到这一点的事实是可悲的curl.exe -d '{"north": "east west"}' https://reqbin.com/echo/post/json
0赞 mklement0 3/28/2021
答案列出了现实情况 - 尽管你(和我)可能不喜欢它 - 并提供了当前可用的最佳解决方法。我同意 PowerShell 在这方面的缺点非常不幸,我一直在努力让他们修复它。选择加入修复可能最终会到来,但它将在多大程度上解决 Windows 上的问题还有待观察。你不喜欢现实情况并不是这个答案的缺点。
0赞 Luiz Felipe 7/27/2022
它来自 cmd.exe 做神奇事情的干草日子,以及 powershell 试图与之兼容,这一切都是公地的不幸悲剧
1赞 mklement0 7/28/2022
@LuizFelipe,归根结底,Windows 应该归咎于它,因为它让应用程序执行自己的命令行解析,为每个人制定自己的规则打开了大门。 当然,它编造了古怪的规则,而 PowerShell 也添加了自己的破坏行为。 不再积极维护,所以我希望 PowerShell 不仅会修复自己的错误,还会弥补 - 唉,只会发生前者,甚至可能需要选择加入。Base64 编码很好(powershell.exe 也支持它),但为了有用,您需要一种从调用 shell 创建它的简单方法。cmd.execmd.execmd.exe
1赞 mklement0 8/6/2022
@LuizFelipe,不幸的是,这不是特例(如果做得好,这将是一件幸事):当前的计划是保留旧的、损坏的行为(在 PowerShell 端损坏)。
0赞 hazartilirot 12/9/2021 #4

以下是我如何在 PowerShell 7.2 中发送 json 请求在此处输入图像描述

评论

0赞 mklement0 3/1/2023
你的答案重复了预先存在的答案中的技术,没有解释,隐藏在许多偶然的信息中。
2赞 Andres 6/10/2022 #5

终于找到了解决方案。Inot 使用一个使用 3 个 (),仅此而已。所以它会是:""""

data={"""password""":"""keypass"""}

评论

0赞 Luiz Felipe 7/27/2022
美丽。谢谢pwsh -nop -c ' bash -c ''printf """""""\\033[38;2;255;0;0mHi\\033[0m"""""""'' '
1赞 mklement0 8/10/2022
@LuizFelipe,将 PowerShell 的 CLI (, ) 与 () 参数一起使用会引入额外的引用注意事项,这些注意事项与此问题的内容是分开的。简而言之:为了从 Windows 上的 PowerShell 外部作为参数的一部分传递,请使用 .在极端情况下,当调用 from 时,请使用 with 和 with - 请参阅此答案powershell.exepwsh-Command-c"-Command\"cmd.exe"^""powershell.exe""pwsh.exe
0赞 GTAE86 5/19/2023
卡在PSVersion 5.1.19041.2673上,最终不得不使用命令行中的三引号。没有尝试过脚本......