Agregue una variable env que contenga espacios a~/.zshrc
export SKIP="-Dskip1 -Dskip2"
export SKIP_NO_SPACES="-Dskip3"
Intenta usarlo
set -x
mvn $SKIP $SKIP_NO_SPACES
El comando que se está ejecutando es en realidad
+-zsh:108> mvn '-Dskip1 -Dskip2' -Dskip3
Sólo se cita la variable que contiene espacios.
¿Cómo evitar que se agreguen comillas simples?
Si no se utilizan comillas ni escapes, se produce un error al abrir el shell:
/.zshrc:export:11: no válido en este contexto: -Dskip2
Respuesta1
Creo que estás (en cierto modo) abusando de las variables de entorno aquí. Ese espacio es parte de la variable, y cuando realiza la expansión de parámetros con $
, simplemente pasará ese espacio al comando. mvn
obtiene un argumento: su contenido variable.
Como observa correctamente Kamil Maciorowski en un comentario, esto es específico de Zsh. Lo que propones funcionaría en Bash si omitieras las comillas:
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
Una alternativa para hacer lo que quieres sería unaalias global(también una característica de Zsh, no de Bash), que se puede sustituir en cualquier parte de una línea. Mantiene sus espacios:
$ alias -g SKIP="-Dskip1 -Dskip2"
$ alias -g SKIP2="-Dskip3"
$ mvn SKIP SKIP2
Esto simplemente "añadirá" la cadena dondequiera que se agregue.
Respuesta2
El problema no tiene nada que ver con citar o escapar, tiene que ver con la división de palabras (o la falta de ella). En la mayoría de los shells, si usa una variable que contiene espacios en blanco sin ponerle comillas dobles, el valor se dividirá en "palabras" según ese espacio en blanco. Entonces, si la variable SKIP
se establece en -Dskip1 -Dskip2
(tenga en cuenta que no hay comillas ni escapes en este valor) y la usa como mvn $SKIP
, se vuelve equivalente a mvn "-Dskip1" "-Dskip2"
.
Pero zsh no es la mayoría de los shells y (de forma predeterminada) no divide palabras. Si la variable está configurada en -Dskip1 -Dskip2
, eso es lo que se pasa al comando,como un solo argumento. Las comillas que ve en el set -x
resultado no están realmente allí, solo se agregan para dejar explícito que la cadena completa se pasa como un único argumento.
Hay un par de formas de decirle a zsh que desea realizar la división de palabras. Puedes usar el =
modificador en la expansión:
mvn ${=SKIP}
O puede activar la división tipo sh para todas las expansiones con una opción de shell:
setopt shwordsplit
mvn $SKIP
...sin embargo, esto puede tener efectos secundarios desagradables, como una división inesperada de cosas que pensaba que eran argumentos únicos y la expansión de cualquier cosa que parezca un comodín de nombre de archivo en una lista de nombres de archivo. La división de palabras del Shell tiende a causar errores, por lo que está deshabilitada de forma predeterminada en zsh. La forma realmente adecuada de almacenar varias cadenas en una variable es utilizar una matriz en lugar de una variable simple:
SKIP=(-Dskip1 -Dskip2)
mvn "${SKIP[@]}"
Esto funcionará en zsh, bash y algunos otros shells (pero no en aquellos que no admiten matrices). Sin embargo, no puedes exportar matrices desde zsh (bueno, puedes ejecutarlo export SKIP
, pero no hace nada). Las matrices son una característica del shell, mientras que las variables de entorno son una característica del sistema operativo que solo admite cadenas simples. ¿Realmente necesitas exportar estas opciones o simplemente las estás usando dentro del shell?
Respuesta3
Aparecen comillas simples en la línea de diagnóstico impresa debido a set -x
. No llegan a mvn
. El contenido de la variable ( -Dskip1 -Dskip2
) llega mvn
como un argumento único porque zsh
no es necesario citar variables rígidamente (lo hace en shells compatibles con POSIX).
El problema parece estar en la forma en que zsh
se expanden las variables. Creo que quieres que se produzca la división de palabras cuando $SKIP
no está entre comillas (como sucede en otros caparazones) pero en zsh
él normalmente no ocurre.
utilizar ${=SKIP}
paraactivar la división de palabras después de la sustitución.
Ejemplo:
% SKIP='-Dskip1 -Dskip2'
% printf "%s\n" $SKIP
-Dskip1 -Dskip2
% printf "%s\n" ${=SKIP}
-Dskip1
-Dskip2
%