sentencias - Expansión de variables dentro de comillas simples en un comando en Bash
sentencias de control en shell script (7)
Quiero ejecutar un comando desde un script de shell bash que tiene comillas simples y algunos otros comandos dentro de comillas simples y una variable
por ejemplo, repo forall -c ''....$variable''
En este formato, $
se escapa y la variable no se expande.
Probé las siguientes variaciones pero fueron rechazadas:
repo forall -c ''...."$variable" ''
repo forall -c " ''....$variable'' "
" repo forall -c ''....$variable'' "
repo forall -c "''" ....$variable "''"
Si sustituyo el valor en lugar de la variable, el comando se ejecuta correctamente.
Por favor, dime dónde me voy mal.
¿Esto funciona para tí?
eval repo forall -c ''....$variable''
A continuación es lo que funcionó para mí -
QUOTE="''"
hive -e "alter table TBL_NAME set location $QUOTE$TBL_HDFS_DIR_PATH$QUOTE"
Al comando repo
no le importa qué tipo de citas recibe. Si necesita expansión de parámetros, use comillas dobles. Si eso significa que terminas teniendo que hacer barras diagonales en muchas cosas, usa comillas simples para la mayoría de ellas, y luego salte de ellas y ve a los dobles para la parte en la que necesitas que se produzca la expansión.
repo forall -c ''literal stuff goes here; ''"stuff with $parameters here"'' more literal stuff''
Explicación sigue, si estás interesado.
Cuando ejecuta un comando desde el shell, lo que ese comando recibe como argumentos es una matriz de cadenas terminadas en nulo. Esas cadenas pueden contener absolutamente cualquier carácter no nulo.
Pero cuando el shell está creando esa matriz de cadenas desde una línea de comandos, interpreta algunos caracteres especialmente; esto está diseñado para hacer que los comandos sean más fáciles (de hecho, posibles) de escribir. Por ejemplo, los espacios normalmente indican el límite entre las cadenas en la matriz; por esa razón, los argumentos individuales a veces se llaman "palabras". Pero un argumento puede sin embargo tener espacios en él; Solo necesitas una forma de decirle al shell que es lo que quieres.
Puedes usar una barra invertida delante de cualquier carácter (incluido el espacio u otra barra invertida) para decirle al shell que trate a ese personaje literalmente. Pero mientras puedes hacer algo como esto:
echo /"Thank/ you./ / That/'ll/ be/ /$4.96,/ please,/"/ said/ the/ cashier
... puede llegar a ser agotador. Así que la cáscara ofrece una alternativa: las comillas. Estos vienen en dos variedades principales.
Las comillas dobles se denominan "comillas de agrupación". Evitan que los comodines y los alias se expandan, pero en su mayoría son para incluir espacios en una palabra. Otras cosas como la expansión de parámetros y comandos (el tipo de cosas señaladas por $
) todavía ocurren. Y, por supuesto, si desea una comilla doble literal dentro de comillas dobles, tiene que hacer una barra inversa:
echo "/"Thank you. That''ll be /$4.96, please,/" said the cashier"
Las comillas simples son más draconianas. Todo entre ellos se toma completamente literalmente, incluyendo barras invertidas. No hay absolutamente ninguna manera de obtener una comilla literal dentro de comillas simples.
Afortunadamente, las comillas en el shell no son delimitadores de palabras ; por sí mismos, no terminan una palabra. Puede ingresar y salir de las citas (o entre diferentes tipos de citas) dentro de la misma palabra para obtener el resultado deseado:
echo ''"Thank you. That''/'''ll be $4.96, please," said the cashier''
Así que eso es más fácil: hay muchas menos barras invertidas, aunque la secuencia de comillas simples de comillas simples, de comillas inversas, requiere un tiempo para acostumbrarse.
Las carcasas modernas han agregado otro estilo de cotización no especificado por el estándar POSIX, en el que la comilla simple a la izquierda está prefijada con un signo de dólar. Las cadenas citadas siguen convenciones similares a las literales de cadena en el lenguaje de programación ANSI C y, por lo tanto, a veces se denominan "cadenas ANSI" y el par $''
... ''
"comillas ANSI". Dentro de tales cadenas, el consejo anterior sobre barras invertidas tomadas literalmente ya no se aplica. En su lugar, se vuelven especiales otra vez; no solo puede incluir una comilla literal o barra diagonal inversa añadiéndole una barra diagonal inversa, sino que el shell también expande los escapes de caracteres ANSI C (como /n
para una nueva línea, /t
para la pestaña y /xHH
para el personaje con código hexadecimal HH
). Sin embargo, de lo contrario, se comportan como cadenas entre comillas simples: no se realiza ninguna sustitución de parámetros o comandos:
echo $''"Thank you. That/'ll be $4.96, please," said the cashier''
Lo importante a tener en cuenta es que la única cadena recibida como argumento para el comando echo
es exactamente la misma en todos estos ejemplos. Una vez que el shell ha terminado de analizar una línea de comando, no hay forma de que el comando que se está ejecutando diga qué se ha citado cómo. Incluso si quisiera.
Dentro de las comillas simples todo se conserva literalmente, sin excepción.
Eso significa que tiene que cerrar las comillas, insertar algo y volver a ingresar.
''before''"$variable"''after''
''before''"''"''after''
''before''/'''after''
Como puede verificar, cada una de las líneas anteriores es una sola palabra para el shell. La concatenación de cadenas se hace simplemente por yuxtaposición. Las comillas (comillas simples o dobles, según la situación) se utilizan para deshabilitar la interpretación de varios caracteres especiales, como espacios en blanco, $
;
... Para ver un buen tutorial sobre citas, vea la respuesta de Mark Reed. También es relevante: ¿Qué personajes deben escaparse en bash?
No concatenar cadenas interpretadas por una concha
Debes evitar absolutamente la construcción de comandos de shell concatenando variables. Esta es una mala idea similar a la concatenación de fragmentos de SQL (inyección de SQL!).
Por lo general, es posible tener marcadores de posición en el comando y suministrar el comando junto con variables para que el destinatario pueda recibirlos de la lista de argumentos de invocación.
Por ejemplo, lo siguiente es muy inseguro. No hagas esto
script="echo /"Argument 1 is: $myvar/""
/bin/sh -c "$script"
Si el contenido de $myvar
no es de confianza, aquí hay un exploit:
myvar=''foo"; echo "you were hacked''
En lugar de la invocación anterior, use argumentos posicionales. La siguiente invocación es mejor, no es explotable:
script=''echo "arg 1 is: $1"''
/bin/sh -c "$script" -- "$myvar"
Tenga en cuenta el uso de tics simples en la asignación al script
, lo que significa que se toma literalmente, sin expansión variable o cualquier otra forma de interpretación.
Las variables pueden contener comillas simples.
myvar=/'....$variable/'
repo forall -c $myvar
EDITAR: (Según los comentarios en cuestión :)
He estado investigando esto desde entonces. Tuve la suerte de tener repo por ahí. Todavía no me queda claro si necesita encerrar sus comandos entre comillas simples por la fuerza. Busqué en la sintaxis del repositorio y no creo que lo necesites. Podría usar comillas dobles alrededor de su comando, y luego usar las comillas simples y dobles que necesite, siempre y cuando salga de las dobles.
solo usa printf
en lugar de
repo forall -c ''....$variable''
use printf para reemplazar el token variable con la variable expandida.
Por ejemplo:
template=''.... %s''
repo forall -c $(printf "${template}" "${variable}")