¿Por qué bash expansion variable retiene comillas?

12
> echo "hi"
hi
> VAR='echo "hi"'
> $VAR
"hi"

¿Por qué es diferente la salida de los comandos anteriores?

Algo similar ocurre con las comillas simples:

> VAR="echo 'hi'"
> $VAR
> 'hi'
Cory Klein
fuente
66
No tenga el hábito de incrustar fragmentos de script ejecutables en variables. Esto tiende a ser difícil en el mejor y evales un campo minado de agujeros de seguridad potenciales que hay que andar con mucho cuidado
jw013
@ jw013 Buen punto y excelentes artículos. Me gusta la cita "Las variables contienen datos, las funciones contienen código". desde el primer enlace, pero para mi uso, los datos que se proporcionan a una función (en este caso at) son códigos. ¿Algún consejo sobre una forma más segura de organizar / recopilar código que se le dará at?
Cory Klein
attoma la shsintaxis como entrada. Por lo tanto, generar entrada para atsignifica generar una shsintaxis válida y correctamente citada a partir de una entrada arbitraria, que no es trivial, por lo que trataría de evitarla si es posible. Realmente ayudaría si pudiera dar un poco más de detalle sobre lo que está tratando de lograr.
jw013
Lo siento, no quería distraerme con demasiados detalles, pero lo que estoy haciendo no es realmente complicado, en mi opinión. Estoy creando un script que toma un "tiempo" y un "mensaje". Luego se ejecuta atdurante el "tiempo" dado y le dice atque ejecute el comando dzen2. dzen2toma el "mensaje" de stdin y también usa algunos otros parámetros estáticos. La dificultad es que necesito canalizar el parámetro "mensaje" del usuario al dzen2comando, pero en realidad no me estoy ejecutando dzen2, estoy diciendo atque lo haga.
Cory Klein
1
superuser.com/questions/360966/… || stackoverflow.com/questions/7454526/…
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

Respuestas:

16

El par adicional de cotizaciones se consumiría solo por un paso de evaluación adicional. Por ejemplo forzado por eval:

bash-4.2$ VAR='echo "hi"'

bash-4.2$ $VAR
"hi"

bash-4.2$ eval $VAR
hi

Pero generalmente es una mala idea poner comandos con parámetros en una cadena. Use una matriz en su lugar:

bash-4.2$ VAR=(echo "hi")

bash-4.2$ "${VAR[@]}"
hi
hombre trabajando
fuente
1
También es importante tener en cuenta que las citas se evalúan de manera diferente; las comillas dobles (") permiten la evaluación de la cadena adjunta, las comillas simples (') imprimen la cadena como literal. Ejemplo: "$(ls)"y '$(ls)'. Esta es la razón por la cual las comillas aparecen en ejemplos de preguntas originales.
Joseph Kern
Una matriz también es una fuente de problemas. El código pertenece a las funciones, los datos a las variables. El ejemplo que presenta solo funciona porque las comillas se eliminan en la división de la matriz. A printf '<%s> ' "${VAR[@]}"mostrará que las citas ya se han eliminado. Si configura VAR VAR=(echo \"hi\")para que tenga comillas, aparecerá el mismo problema nuevamente, $ ${VAR[@]}se imprimirá"hi"
9

La eliminación de comillas solo ocurre en las palabras de entrada originales, no en el resultado de expansiones. Las citas que forman parte de las variables expandidas no se tocan.

jw013
fuente
2

Si retrocede un poco, puede ver por qué la sustitución de variables debería conservar las comillas.

El punto de las comillas en un shell Unix / Linux / BSD es mantener juntas las piezas de una cadena que de otro modo se analizarían como cadenas múltiples. Dado que, por defecto, un shell utiliza espacios en blanco como separador de tokens, una cadena con espacios (como "uno dos tres") si no se cita o escapa de alguna manera, se analizaría como 3 cadenas: "uno", "dos" y "tres".

Si un programador quiere una cadena con el valor de alguna variable interpolada:

VAR=two
STRING="one $VAR three"

el shell no debería eliminar las comillas: la cadena que contiene espacios se analizaría como 3 cadenas más pequeñas.

Bruce Ediger
fuente