我正在使用kubectl和 zsh,我想将命名空间标志存储在环境变量中。
而不是写:
kubectl get pods -n mynamespace
我想做类似的事情:
n='-n mynamespace'
kubectl get pods $n
但这样做,我得到:
No resources found in mynamespace namespace.
in
注意单词和之间的两个空格mynamespace
。
如果我运行kubectl get pods -n mynamespace
,我会获得正确的输出:
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 16m
这里会发生什么?为什么输出中的单词in
和之间有两个空格mynamespace
?以及如何将命名空间标志存储在环境变量中?
zsh 不对变量执行分词,而是将其值作为单个参数传递。我这里没有 kubectl,但你可以用任何东西重现该行为,例如 mkdir:
您可以使用以下方法调用相同的错误:
您可以使用以下命令查看 zsh 真正在做什么
strace -f mkdir $var
:正如this answer on SO中所建议的, 您需要启用分词,例如:
在您的情况下,它将是:
不要将 shell 变量(或任何语言的变量)与环境变量混淆。环境变量是
var=value
语法中的字符串数组,在执行时与参数数组一起传递给命令。与命令行参数一样,它们用于将字符串从一个命令传递到另一个不相关的命令。Shell 具有这样的特殊性,它们将一些标量变量映射到它们在启动时收到的一些环境变量(名称是有效的 shell 变量名并且不会与特殊的 shell 变量冲突的环境变量),而其他语言使用 API,例如至于
getenv()
检索它们(或将它们映射到特殊的关联数组,如 perl 的ENVIRON
ofawk
或%ENV
of ),但这并不意味着 shell 不能拥有自己的变量,也不限于标量变量。如果要在变量中存储多个值,则可以使用数组/列表变量。zsh 从 1991 年的 2.0 版本开始支持数组(早于 bash),实际上是 shell 引入了
array=(foo bar)
声明它们的语法(类似于set array=(foo bar)
70 年代后期的 csh),现在 ksh93、bash、mksh 和 yash 也支持。在
zsh
中,你会这样做:在 中
yash
,你会这样做:而在 ksh93/bash 中(zsh 也支持,它还具有不丢弃空元素的优点,并且
yash
):现在,数组不能导出为环境变量,它们只是非 NUL 字节的纯字符串。
如果您必须将这两个参数
kubectl
作为一个环境变量传递,则需要以某种方式使用某种形式的编码将它们组合起来,以从字符串数组中获取一个字符串,然后将其拆分以将这两个参数取回 forkubectl
。您选择将它们与空格连接起来作为粗略的编码。请注意,这意味着每个元素都不能包含空格。
要使用任意分隔符连接单词, in
zsh
,您可以使用j
参数扩展标志,并拆分s
参数扩展标志:然后从
zsh
在该环境中调用的另一个ENV_VAR
环境变量已映射到$ENV_VAR
shell 变量:在没有参数扩展标志的 bash 或 ksh93 中,您可以使用第一个字符(恰好是其默认值中的空格字符)
"${array[*]}"
连接数组元素,并使用 split+glob 进行拆分:$IFS
在另一个
bash
/ksh93
在那个环境中:您也可以在 中执行此操作
zsh
,但仅限在 sh 或 ksh 仿真模式下。默认情况下,zsh 不会在不带引号的参数扩展时执行 split+glob,您必须明确请求每个:$=var
用于拆分,$~var
用于通配。因此,如果由于某种原因您想使用 IFS 拆分而不是j
/s
参数扩展标志,您可以这样做:现在,我不知道
kubectl
,但是对于以标准方式解析选项的应用程序(例如使用标准getopt()
C 函数),对于带有参数的选项,例如 withgrep -e expression
,您可以传递两个-e
andexpression
参数或一个-eexpression
参数,所以在这里,您仍然可以将-n
其及其mynamespace
参数存储在标量变量中:(请注意,如果
$option
是空的,它的扩展,因为它没有被引用不会导致任何参数被传递给kubectl
。虽然这(以及空数组元素被丢弃的事实)可能被认为是一个错误,但在这里它会碰巧是你想要什么)。