Cómo usar una variable de entorno dentro de una cadena entre comillas en Bash

91

Probé varias formas de lo siguiente en un script bash:

#!/bin/bash
svn diff $@ --diff-cmd /usr/bin/diff -x "-y -w -p -W $COLUMNS"

Pero no puedo hacer que la sintaxis expanda correctamente la COLUMNSvariable de entorno.

Probé varias formas de lo siguiente:

svn diff $@ --diff-cmd /usr/bin/diff -x '-y -w -p -W $COLUMNS'

y

svn diff $@ --diff-cmd /usr/bin/diff -x '-y -w -p -W ${COLUMNS}'

y

eval svn diff $@ --diff-cmd /usr/bin/diff -x "-y -w -p -W $COLUMNS"

Sugerencias

Jamie
fuente
entonces, ¿qué producen esos ejemplos en su caso? ¿Y qué quieres que produzcan?
el comando fuera del script está funcionando?
dfa
¿Has probadosvn diff $@ --diff-cmd /usr/bin/diff -x "-y -w -p -W ""$COLUMNS"
Qian Chen
Por cierto, usar sin $@comillas lo hace exactamente igual que $*, lo que quiere decir que se divide "foo bar"en dos argumentos separados, fooy bar. Si desea conservar la lista de argumentos original tal como se le proporcionó, lo desea "$@".
Charles Duffy

Respuestas:

16

Si no está seguro, puede usar la solicitud 'cols' en la terminal y olvidar COLUMNAS:

COLS=$(tput cols)
TheBonsai
fuente
Por el motivo que sea, esta es la única solución que pude poner a trabajar desde esta página (a partir del 11 de mayo de 10:38 ET). Gracias
Jamie
398

Solo una nota / resumen rápido para cualquiera que haya venido aquí a través de Google en busca de la respuesta a la pregunta general formulada en el título (como yo). Cualquiera de los siguientes debería funcionar para obtener acceso a las variables de shell entre comillas:

echo "$VARIABLE"
echo "${VARIABLE}"

El uso de comillas simples es el problema principal. Según el Manual de referencia de Bash :

Incluir caracteres entre comillas simples ( ') conserva el valor literal de cada carácter dentro de las comillas. Una comilla simple no puede aparecer entre comillas simples, incluso cuando esté precedida por una barra invertida. [...] Encerrar caracteres entre comillas dobles ( ") preserva el valor literal de todos los caracteres dentro de las comillas, con la excepción de $, `, \, y, cuando se habilita la expansión de historia, !. Los caracteres $y `conservan su significado especial entre comillas dobles (ver Expansiones de Shell). La barra invertida mantiene su significado especial sólo cuando es seguida por uno de los siguientes caracteres: $, `, ",\o nueva línea. Entre comillas dobles, se eliminan las barras diagonales inversas seguidas por uno de estos caracteres. Las barras invertidas que preceden a los caracteres sin un significado especial no se modifican. Una comilla doble puede estar entre comillas dobles precediéndola con una barra invertida. Si está habilitado, la expansión del historial se realizará a menos que una que !aparezca entre comillas dobles se escape usando una barra invertida. La barra invertida que precede al !no se elimina. Los parámetros especiales *y @tienen un significado especial cuando están entre comillas dobles (consulte Expansión de parámetros de Shell).

En el caso específico planteado en la pregunta, $ COLUMNS es una variable especial que tiene propiedades no estándar (consulte la respuesta de lhunath arriba).

Recursivamente irónico
fuente
20
En el caso de las comillas simples, tal vez esta solución ayude: 'before'"$variable"'after'(como se indica en esta respuesta: stackoverflow.com/a/13802438/2254346 )
MakisH
¡Gran respuesta! Tuve el mismo problema de referir mi variable env entre comillas simples. Una vez que cambié mi comilla simple a comillas dobles, mi variable env se expandió como se esperaba.
Binita Bharati
14

Tenga en cuenta que COLUMNSes:

  1. NO es una variable de entorno. Es un parámetro bash ordinario que establece el propio bash.
  2. Se configura automáticamente al recibir una SIGWINCHseñal.

Ese segundo punto generalmente significa que su COLUMNSvariable solo se establecerá en su shell interactivo , no en un script bash.

Si su script stdinestá conectado a su terminal, puede buscar manualmente el ancho de su terminal preguntando a su terminal:

tput cols

Y para usar esto en su comando SVN:

svn diff "$@" --diff-cmd /usr/bin/diff -x "-y -w -p -W $(tput cols)"

(Nota: debe cotizar "$@" y mantenerse alejado de eval;-))

lhunath
fuente
Gracias por la información; saber lo que está pasando aporta una sensación de catarsis al tema.
Jamie
2

El siguiente script me funciona para múltiples valores de $COLUMNS. Me pregunto si no está configurando COLUMNSantes de esta llamada.

#!/bin/bash
COLUMNS=30
svn diff $@ --diff-cmd /usr/bin/diff -x "-y -w -p -W $COLUMNS"

¿Puedes hacer eco $COLUMNSdentro de tu secuencia de comandos para ver si está configurado correctamente?

Alex B
fuente
Boo, hiss re: unquoted $@- que divide un solo parámetro "two words"en dos parámetros separados, twoy words. Debería "$@"pasar la lista de argumentos exactamente como se le dio.
Charles Duffy
0

Lo está haciendo bien, así que supongo que algo más tiene la culpa (¿no exportar COLUMNAS?).

Un truco para depurar estos casos es hacer un comando especializado (un cierre para los chicos del lenguaje de programación). Cree un script de shell llamado diff-columnas haciendo:

exec /usr/bin/diff -x -y -w -p -W "$COLUMNS" "$@"

y solo usa

svn diff "$@" --diff-cmd  diff-columns

De esta manera, su código es más limpio de leer y más modular (enfoque de arriba hacia abajo), y puede probar el código de columnas de diferencias completamente por separado (enfoque de abajo hacia arriba).

Colas Nahaboo
fuente
La línea de comandos se analiza antes de que se bifurque el proceso, por lo que no exportar COLUMNAS no puede ser el problema.
Peter van der Heijden
1
Dice que su código es parte de un script bash, por lo que puede ser el problema.
Colas Nahaboo