以下命令在 Ubuntu bash 上工作正常:
kubectl patch deployment wapi-backend-d1 --patch '{"spec": {"template": {"metadata": {"labels": {"date": "test"}}}}}'
相同的命令在 Windows Powershell 控制台 (ISE) 中不起作用。
错误是:
kubectl : Error from server (BadRequest): invalid character 's' looking for beginning of object key string
At line:1 char:1
+ kubectl patch deployment wapi-backend-d1 --patch '{"spec": {"template ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (Error from serv...ject key string:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
Powershell控制台版本为:
PS > $PSVersionTable
Name Value
---- -----
PSVersion 5.1.14409.1005
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.14409.1005
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
我也尝试了具有不同补丁值的命令,因为我看到有人写道,如果已经应用了补丁,则补丁可能会失败。
路径/spec/template/metadata/labels/date 确实存在于部署的 yaml 中,所以这也不是问题。
我认为它可能与 kubectl 在 Powershell 中与引号相关的不同工作有关,但找不到使其工作的方法。
我试过了
kubectl patch deployment wapi-backend-d1 --patch "{"spec": {"template": {"metadata": {"labels": {"date": "test123"}}}}}"
但这导致
Error from server (NotFound): deployments.extensions "spec\: {\template\: {\metadata\: {\labels\: {\date\: \test123\}}}}}" not found
Powershell上的命令应该是什么?
有关详细且非常有用的背景信息,请参阅mklement0的答案
在经历了很多挫折之后,我决定列出我尝试过的所有报价转义变体,并想出了一个,它突然奏效了! 所以,在这里分享它:
kubectl patch deployment wapi-backend-d1 --patch '{"spec": {"template": {"metadata": {"labels": {"date": "test123"}}}}}'
这是如何使用 kubectl 补丁与 Powershell
另外,请注意:我实际上试图用时间戳修补它以触发滚动更新而不更改容器映像的标签(因此设置图像对我没有帮助)。
当您尝试将 JSON 放入变量中,然后使用变量调用 kubectl 补丁时,您再次遇到转义的麻烦。这就是我最终得到的:
$patchRequest = @{
spec = @{
template = @{
metadata = @{
labels = @{
date = ((((Get-Date -Format o)).replace(':','-').replace('+','_')))
}
}
}
}
}
$patchJson = ((ConvertTo-Json -InputObject $patchRequest -Compress -Depth 10))
$patchJson = $patchJson.replace('"','"')
kubectl patch deployment wapi-backend-d1 --patch $patchJson
您在自己的答案中找到了正确的解决方案,但让我尝试从概念上分解它:
在传递给外部程序的字符串参数中嵌入"
(双引号):
-
(a) 首先 - 明智且不可避免地 - 您需要满足PowerShell关于在带引号的字符串中嵌入
"
字符的语法要求。 -
(b)然后 - 此步骤不是必需的 - 您需要
转义嵌入的
"
字符,您希望外部程序看到。- 这是一个长期存在的,令人讨厌的错误,直到PowerShell 7.2.x- 请参阅此答案 - 在7.3 +中已修复,在Windows上有选择性例外- 请参阅此答案。
对于 (a),您有以下选择:
-
'...'
-quoteing(单引号),即一个逐字字符串,您可以在其中按原样"
:'{ "spec": "none" }'
-
'...'
中的所有内容都是逐字记录的(字面意思)- 不会发生扩展(字符串插值)。
-
"..."
-quoteing(双引号),即一个可扩展的字符串,您可以在其中使用`"
或""
嵌入"
字符:"{ `"spec`": `"none`" }"
-`
是PowerShell的一般转义字符。"{ ""spec"": ""none"" }"
-"
特定转义(加倍)-
"..."
的内容会受到扩展(字符串内插)的影响,这意味着您可以在此类字符串中引用变量 ($var
) 或子表达式 ($(1 + 2)
),PowerShell 将其替换为其值 - 有关 PowerShell 的可扩展字符串的详细信息,请参阅此答案。
如果要将此类字符串传递给其他PowerShell命令(cmdlet、函数或脚本),则无需进一步操作;例如:
PS> Write-Output '3" of rain'
3" of rain
Re (b)- 即将此类字符串传递给外部程序- 您还需要转义嵌入的
"
字符:
将手动转义应用于上述示例:
'{ "spec": "none" }'
"{ `"spec`": `"none`" }"
"{ ""spec"": ""none"" }"
以编程方式将转义应用于预先存在的字符串:
将逐字
:"
替换为逐字"
,以及任何先前存在的、紧接在前面的
\
$str = '3" of rain'; $escapedStr = $str -replace '([\]*)"', '$1$1"'
也就是说,若要使外部程序最终逐字查看值
3" of rain
,必须从 PowerShell 传递文本值3" of rain
。这种转义是PowerShell作为shell应该在幕后自动执行的操作,但目前没有。
Windows PowerShell中还有一个额外的错误 -自从在PowerShellCore中修复以来 - 错误地处理具有不平衡的嵌入
例如,"
字符的字符串。 如果"
是第一个单词的一部分:- 上述技术不适用于文字值,例如
3" of rain
;也就是说,将其转义为'3" of rain'
不能按预期工作 - 相反,您必须使用以下怪物:`"3`" of rain`"
,从技术上讲,这是一系列单独的,未引用的参数,这意味着(a)不支持字符串单词之间的多个空格(它们折叠为单个空格)和(b)PowerShell元字符,例如& < > $ & | @ {
必须是单独`
逃逸。 - 请注意,仅当
"
是值中第一个单词的一部分时,并且仅当第一个单词前面没有空格时,错误才会出现(尽管带有前导空格的参数很少有用);例如,'3 " of rain'
会再次起作用,因为不平衡的"
不是第一个单词的一部分。
- 上述技术不适用于文字值,例如
示例:
下面使用choice.exe
作为示例外部程序,因为它可以重新调整用途(通过选项/d Y /t 0
)以仅回显给定的提示字符串,这显示了它如何接收从 PowerShell 传递的字符串:
& {
# Note: For preview versions of v7.2, deactivate the experimental
# feature that fixes the problem, so as to show the original problem.
$PSNativeCommandArgumentPassing = 'Legacy'
# Use manual -escaping to pass what should be received as
# verbatim { "spec": "none" } to an external program.
choice /m '{ "spec": "none" }' /d Y /t 0
}
上面的输出{ "spec": "none" } [Y,N]?Y
,显示手动转义的"
字符被外部程序作为逐字"
字符接收。
对我来说这有效 Kubectl 补丁 cronjobs address-update-cron-job -p "{"spec" : {"suspend" : true }}">