Como exportar corretamente variáveis ​​env contendo espaços no ZSH

Como exportar corretamente variáveis ​​env contendo espaços no ZSH

Adicione uma variável env contendo espaços para~/.zshrc

export SKIP="-Dskip1 -Dskip2"
export SKIP_NO_SPACES="-Dskip3"

Tente usá-lo

set -x  
mvn $SKIP $SKIP_NO_SPACES

O comando que está sendo executado é na verdade

+-zsh:108> mvn '-Dskip1 -Dskip2' -Dskip3

Somente a variável que contém espaços é citada.

Como evitar que aspas simples sejam adicionadas?

Se não estiver usando aspas/escapamento, haverá um erro ao abrir o shell:

/.zshrc:export:11: não é válido neste contexto: -Dskip2

Responder1

Acho que você está (meio que) abusando de variáveis ​​de ambiente aqui. Esse espaço faz parte da variável e, quando você estiver realizando a expansão de parâmetros com $, ele simplesmente passará esse espaço para o comando. mvnrecebe um argumento – o conteúdo da sua variável.

Como Kamil Maciorowski observa corretamente em um comentário, isso é específico do Zsh. O que você está propondo funcionaria no Bash se você deixasse as aspas de fora:

bash-5.0$ export test="foo bar"
bash-5.0$ ls $test
ls: bar: No such file or directory
ls: foo: No such file or directory
bash-5.0$ ls "$test"
ls: foo bar: No such file or directory

Uma alternativa para fazer o que você quer seria umapelido global(também um recurso do Zsh, não do Bash), que pode ser substituído em qualquer lugar da linha. Mantém seus espaços:

$ alias -g SKIP="-Dskip1 -Dskip2"
$ alias -g SKIP2="-Dskip3"
$ mvn SKIP SKIP2

Isso simplesmente "acrescentará" a string onde quer que seja adicionada.

Responder2

O problema não tem nada a ver com citar ou escapar, tem tudo a ver com divisão de palavras (ou a falta dela). Na maioria dos shells, se você usar uma variável que contenha espaços em branco sem colocar aspas duplas, o valor será dividido em "palavras" com base nesse espaço em branco. Portanto, se a variável SKIPestiver definida como -Dskip1 -Dskip2(observe que não há aspas ou escapes neste valor) e você a usar como mvn $SKIP, ela se tornará equivalente a mvn "-Dskip1" "-Dskip2".

Mas zsh não é a maioria dos shells e (por padrão) não faz divisão de palavras. Se a variável estiver definida como -Dskip1 -Dskip2, é isso que está sendo passado para o comando,como um único argumento. As aspas que você vê na set -xsaída não estão realmente lá, elas são apenas adicionadas para deixar explícito que a string inteira está sendo passada como um único argumento.

Existem algumas maneiras de dizer ao zsh que você deseja que a divisão de palavras seja feita. Você pode usar o =modificador na expansão:

mvn ${=SKIP}

Ou você pode ativar a divisão tipo sh para todas as expansões com uma opção de shell:

setopt shwordsplit
mvn $SKIP

...no entanto, isso pode ter efeitos colaterais desagradáveis, como divisão inesperada de coisas que você pensava serem argumentos únicos e expansão de qualquer coisa que pareça um curinga de nome de arquivo em uma lista de nomes de arquivos. A divisão de palavras do shell tende a causar bugs, e é por isso que está desabilitada por padrão no zsh. A maneira realmente adequada de armazenar múltiplas strings em uma variável é usar um array em vez de uma variável simples:

SKIP=(-Dskip1 -Dskip2)
mvn "${SKIP[@]}"

Isso funcionará em zsh, bash e alguns outros shells (mas não aqueles sem suporte a array). No entanto, você não pode exportar matrizes do zsh (bem, você pode executar export SKIP, mas isso não faz nada). Matrizes são um recurso do shell, enquanto variáveis ​​de ambiente são algo do sistema operacional que suporta apenas strings simples. Você realmente precisa exportar essas opções ou está apenas usando-as dentro do shell?

Responder3

Aspas simples aparecem na linha de diagnóstico impressa por causa de set -x. Eles não conseguem mvn. A variável content ( -Dskip1 -Dskip2) é mvnconsiderada um argumento único porque zshvocê não precisa citar variáveis ​​rigidamente (você faz isso em shells compatíveis com POSIX).

O problema parece estar na forma como zshexpande as variáveis. Acho que você deseja que a divisão de palavras ocorra quando $SKIPnão está entre aspas (como acontece em outras conchas) mas zshnormalmente não ocorre.

Use ${=SKIP}paraacionar divisão de palavras após substituição.

Exemplo:

% SKIP='-Dskip1 -Dskip2' 
% printf "%s\n" $SKIP   
-Dskip1 -Dskip2
% printf "%s\n" ${=SKIP}
-Dskip1
-Dskip2
% 

informação relacionada