当 kubectl 通过 ssh 运行时,如何传递命令类参数?如果我不使用 ssh 运行,ls 的 -l 参数将传递给 pod shell。我尝试过退出、放入引号等,但都不起作用。
ssh [email protected] kubectl exec -it mypod -n mynamespace -- sh -c ls -l
答案1
有用的资源:
如果你知道要在远程 shell 中执行的确切命令,那么你可以为本地 shell 编写一个命令。我认为远程 shell 的命令应该不是是:
# wrong
kubectl exec -it mypod -n mynamespace -- sh -c ls -l
因为它会运行kubectl
那会运行sh -c ls -l
。在本地尝试后一个代码,你会看到它不会运行ls -l
。这是因为-l
不属于 的代码sh
被告知要运行。 的代码sh
应该是单身的之后的选项参数-c
;其他参数(如果有)不同(比较这个问题)。
这意味着最终您需要一个在 shell 中看起来像这样的命令: 。如果是它的一个参数,sh -c 'ls -l'
您kubectl exec
将运行它。因此,您需要在远程 shell 中执行此命令:ls -l
kubectl exec -it mypod -n mynamespace -- sh -c 'ls -l'
# or
kubectl exec -it mypod -n mynamespace -- sh -c "ls -l"
(我们选择后者。)现在您知道要在远程 shell 中执行的确切命令。将其ssh
作为单个参数传递给本地:
ssh [email protected] 'kubectl exec -it mypod -n mynamespace -- sh -c "ls -l"'
外部(单)引号将被本地 shell 删除,但由于它们,ssh
将获得较大的代码字符串 ( kubectl … "ls -l"
) 作为单个参数。代码将包含内部(双)引号。这些将被远程 shell(由 SSH 服务器生成)删除,但由于它们,kubectl
将获得较小的代码字符串 ( ls -l
) 作为单个参数;因此它将生成sh
将代码作为单个参数的程序。
在这种情况下,哪个引用使用单引号,哪个使用双引号并不重要。重要的是引号对是否不同(例如,a "b "c""
引号既不是内引号也不是外引号,它们是两个单独的对,c
没有使用引号)。
请注意,不同的工具以不同的方式消化它们的参数并为下一步构建“代码”:
ssh
可以连接多个参数来为远程 shell 构建代码(这就是你的尝试成功的原因);然后远程 shell 会解释单个字符串。当我需要保护某些东西(例如引号)免受本地 shell 的影响时(这里就是这种情况),我更喜欢在本地引用整个代码并将其ssh
作为单个参数传递给;但这是我的选择。因此,
ssh
从一个或多个参数构建一个字符串。kubectl exec
将后面的参数--
视为数组。在我们的例子中,它sh
使用参数-c
和运行ls -l
(在您的尝试中,参数是-c
、ls
和-l
)。因此
kubectl exec
不构建任何字符串。它从参数数组中构建一个要执行的数组。sh -c
仅将后面的一个参数解释-c
为 shell 代码。它不会像ssh
can 那样连接多个参数。
想象sh -c
一下在本地 shell 中运行代码的接口;以及ssh …@…
在远程 shell 中运行代码的接口。它们很相似,每个都会生成一个 shell,该 shell 将解释以单个字符串形式编写的代码。但它们是不同的,不同之处在于字符串的创建方式:sh -c
从一个参数中获取代码,ssh
从可能的许多参数中构建代码。kubectl exec
是一个在容器中运行可执行文件的接口。它与其他两个接口最大的不同之处在于它直接将其参数用作数组。
你真的需要吗sh -c
?我认为在这种情况下
ssh [email protected] 'kubectl exec -it mypod -n mynamespace -- ls -l'
就足够了。请注意,如果您"ls -l"
在此处使用(仍在单引号代码中),kubectl exec
则会尝试运行名为ls -l
(而不ls
是以-l
作为参数的)的可执行文件。在这里,您不想将内部引号应用于ls -l
。
另一方面,以下任何一种:
ssh [email protected] kubectl exec -it mypod -n mynamespace -- ls -l
ssh [email protected] kubectl exec -it mypod -n mynamespace -- "ls -l"
ssh [email protected] kubectl exec -it "mypod -n mynamespace -- ls" -l
之所以有效,是因为ssh
将为远程 shell 构建相同的字符串(尽管来自不同数量的不同参数)。最后一个例子特别奇怪;它在本地将多个“最终”参数收集为一个,似乎破坏了逻辑(我的意思是ls
与有关-l
而不是与有关-n
,对吧?)。尽管如此,它还是有效的,原因是该方法ssh
从多个字符串中构建了一个字符串。
sh -c
在ls -l
您拥有真正需要 shell 的任何东西(例如带有的管道|
、像 这样的重定向的命令>file
、像 这样的 shell 语法if
)的情况下是必须的。
您的命令(或我的固定命令)由几个嵌套工具组成。在每个步骤中,一个(外部)工具以某种方式消化其参数并以某种方式在同一台或另一台主机上生成另一个(内部)工具。最终结论是您需要了解您正在使用的所有工具,它们解析参数的方式以及调用下一个工具的方式。请注意,在我们的示例中,之前有一个本地 shell,ssh
服务器上的 SSH 守护程序与 之间有一个远程 shell kubectl
;您还需要考虑每个隐式 shell。