2009-02-18 27 views
9

Tengo algunos problemas con la división de palabras en la expansión de variable bash. Quiero poder almacenar una lista de argumentos en una variable y ejecutarla, pero cualquier argumento de palabras múltiples citado no está evaluando cómo esperaba que lo hicieran.¿Cómo puedo pasar una lista completa de argumentos en bash manteniendo los argumentos de mulitword juntos?

Explicaré mi problema con un ejemplo. Digamos que tenía una función decho que imprime cada parámetro de posición en su propia línea:

#!/bin/bash -u 
while [ $# -gt 0 ]; do 
    echo $1 
    shift 
done 

Ok, si voy decho a b "c d" me sale:

[~]$ decho a b "c d" 
a 
b 
c d 

¿Qué es lo que espero y deseo. Pero por otro lado si consigo la lista de argumentos de una variable consigo esto:

[~]$ args='a b "c d"' 
[~]$ decho $args 
a 
b 
"c 
d" 

que no es lo que quiero. Puedo ir:

[~]$ echo decho $args | bash 
a 
b 
c d 

Pero eso parece un poco torpe. ¿Hay una mejor manera de hacer que la expansión de $args en decho $args sea dividida por palabras de la manera que esperaba?

+0

FYI, 'echo $ 1' es bastante desafortunado - que sustituye, f'rinstance, un argumento de' '* con una lista de nombres de archivo en el directorio actual. 'echo" $ 1 "' sería menos propenso a riesgos. –

Respuesta

4

que puede utilizar:

eval decho $args 
0

Ha intentado:

for arg in "[email protected]" 
do 
     echo "arg $i:$arg:" 
     let "i+=1" 
done 

debe ceder algo como:

arg 1: a 
arg 2: c d 

en su caso.

Directamente desde la memoria, no hay garantía :-)

+0

Esta función realiza exactamente lo mismo que decho. El problema está en llamar a Decho, no en Decho. –

0

hmmm .. eval decho $args también funciona:

[~]$ eval decho $args 
a 
b 
c d 

y yo podría ser capaz de hacer algo con arreglos bash usando "${array[@]}" (que funciona como "[email protected]"), pero luego tendría que escribir código para cargar la matriz, lo que sería un problema.

2

Puede mover el eval dentro de la secuencia de comandos:

#!/bin/bash -u 
eval set -- $* 
for i; 
do 
    echo $i; 
done 

Ahora usted puede hacer:

$ args='a b "c d"' 
$ decho $args 
a 
b 
c d 

pero tendrá que citar los argumentos, si los pases en la CL:

$ decho 'a b "c d"' 
a 
b 
c d 
0

Es fundamentalmente erróneo intentar pasar una lista de argumentos almacenada en una variable, a un comando.

Presumiblemente, si tiene un código en alguna parte para crear una variable que contenga las args previstas.para un comando, a continuación, se puede cambiar a almacenar en su lugar los argumentos en una variable de matriz:

decho_argv=(a b 'c d') # <-- easy! 

Entonces, en lugar de cambiar el comando "Decho" para dar cabida a los argumentos tomados de una variable normal (que romperá su capacidad para manejar argumentos normales) que puede hacer:

decho "${decho_argv[@]}" # USE DOUBLE QUOTES!!! 

Sin embargo, si usted es la situación en la que usted está tratando de tomar la entrada arbitraria que se espera que sea campos de cadena correspondiente a argumentos posicionales de mando previstos, y desea pasa esos argumentos a un comando, entonces deberías en lugar de usar una variable, leer los datos en una matriz.

Tenga en cuenta que las sugerencias que ofrecen el uso de eval para establecer los parámetros posicionales con los contenidos de una variable común son extremadamente peligrosas.

Porque exponer el contenido de una variable a la eliminación de comillas y división de palabras en la línea de comandos no permite evitar que los metacaracteres de shell en la cadena de la variable causen estragos.

Por ejemplo, imagina en el siguiente ejemplo, si la palabra "hombre" fue sustituida por las dos palabras "RM" y "rf" y la última palabra arg era "*":

no hacen esto :

> args='arg1 ; man arg4' 
> eval set -- $args 
No manual entry for arg4 
> eval set -- "$args"  # This is no better 
No manual entry for arg4 
> eval "set -- $args"  # Still hopeless 
No manual entry for arg4 

> eval "set -- '$args'" # making it safe also makes it not work at all! 
> echo "$1" 
arg1 ; man arg4 
Cuestiones relacionadas