Estou trabalhando com kubectl e zsh e gostaria de armazenar o sinalizador de namespace em uma variável de ambiente.
Em vez de escrever:
kubectl get pods -n mynamespace
Eu gostaria de fazer algo como:
n='-n mynamespace'
kubectl get pods $n
mas fazendo isso, obtenho:
No resources found in mynamespace namespace.
Observe os dois espaços entre as palavras in
e mynamespace
.
Se eu executar kubectl get pods -n mynamespace
, obtenho a saída correta:
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 16m
o que acontece aqui? Por que há dois espaços na saída entre as palavras in
e mynamespace
? E como posso armazenar o sinalizador de namespace em uma variável de ambiente?
zsh não está executando a divisão de palavras na variável e passa seu valor como um único parâmetro. Eu não tenho kubectl aqui, mas você pode reproduzir o comportamento com qualquer coisa, por exemplo mkdir:
Você pode invocar o mesmo erro com:
Você pode ver o que o zsh está realmente fazendo usando
strace -f mkdir $var
:Conforme sugerido nesta resposta no SO, você precisa habilitar a divisão de palavras, por exemplo:
No seu caso seria:
Não confunda variáveis de shell (ou variáveis de qualquer linguagem) com variável de ambiente . As variáveis de ambiente são um array de strings na
var=value
sintaxe que é passado para um comando junto com o array de argumentos quando ele está sendo executado. Como os argumentos de linha de comando, eles são usados para passar strings de um comando para outro comando não relacionado.Os shells têm essa particularidade de mapear algumas de suas variáveis escalares para algumas das variáveis de ambiente que recebem na inicialização (aquelas cujo nome são nomes de variáveis de shell válidos e não entram em conflito com variáveis de shell especiais), enquanto outras linguagens usam APIs como como
getenv()
recuperá-los (ou mapeá-los para um array associativo especial como oENVIRON
ofawk
ou o%ENV
of perl), mas isso não significa que os shells não podem ter variáveis próprias nem estão limitados a variáveis escalares.Se você quiser armazenar mais de um valor em uma variável, você usaria uma variável array/list. O zsh suporta arrays desde a versão 2.0 em 1991 (muito antes do bash), na verdade é o shell que introduziu a
array=(foo bar)
sintaxe para declará-los (semelhante aoset array=(foo bar)
do csh do final dos anos 70), agora também suportado pelo ksh93, bash, mksh e yash.Em
zsh
, você faria:Enquanto estiver em
yash
, você faria:E em ksh93/bash (também suportado por zsh, onde também tem a vantagem de não descartar os elementos vazios, e
yash
):Agora, arrays não podem ser exportados como variáveis de ambiente, que são apenas strings simples de bytes não-NUL.
Se você tiver que passar esses dois argumentos
kubectl
como uma variável de ambiente, precisará combiná-los de alguma forma usando alguma forma de codificação para obter uma string de uma matriz de strings e depois dividi-la para obter esses dois argumentos de volta parakubectl
.Você escolheu juntá-los com espaços como uma codificação bruta. Observe que isso significa que cada elemento não pode conter espaços.
Para unir palavras com um separador arbitrário, em
zsh
, você pode usar oj
sinalizador de expansão de parâmetro e dividir os
sinalizador de expansão de parâmetro:Em seguida, de outro
zsh
invocado nesse ambiente, onde aENV_VAR
variável de ambiente foi mapeada para a$ENV_VAR
variável do shell:No bash ou ksh93 que não possuem sinalizadores de expansão de parâmetro, você pode usar
"${array[*]}"
para unir elementos da matriz com o primeiro caractere de$IFS
(que é o caractere de espaço em seu valor padrão) e split+glob para dividir:E em outro
bash
/ksh93
nesse ambiente:Você também pode fazer isso em
zsh
, mas apenas quando estiver no modo de emulação sh ou ksh. Por padrão, o zsh não faz split+glob em expansões de parâmetros sem aspas, você precisa solicitar cada um explicitamente:$=var
para divisão,$~var
para globbing. Portanto, se por algum motivo você quiser usar a divisão IFS em vez dos sinalizadores de expansãoj
/s
parâmetro, você pode fazer:Agora, eu não sei sobre
kubectl
, mas para aplicativos que analisam opções da maneira padrão (como com agetopt()
função C padrão), para opções que recebem um argumento, como comgrep -e expression
, você pode passar dois argumentos-e
eexpression
ou um-eexpression
argumento, então aqui, você ainda pode armazenar isso-n
e seumynamespace
argumento em uma variável escalar com:(observe que, se
$option
estivesse vazio, sua expansão, porque não está entre aspas, não resultaria em nenhum argumento a ser passado parakubectl
. Enquanto isso (e o fato de que elementos de matriz vazios são descartados) poderia ser considerado um recurso incorreto, mas aqui aconteceria ser o que você quer).