2011-03-09 17 views
10

He estado leyendo citas en bash aquí y en todas partes, pero no recibí ayuda para resolver este problema.Problema de Bash con eval, variables y citas

Lo que pasa es que tengo un pequeño script para hacer copias de seguridad en un ciclo.

Si no uso eval entonces tengo problemas con la variable $OPTIONS en rsync.

Pero si yo utilizo eval entonces el problema va a la variable $CURRENT_DIR ...

rsync devuelve el siguiente mensaje: 'inesperado arg locales:/ruta/a'

He intentado todas las forma de citar la variable $CURRENT_DIR

CURRENT_DIR="/path/with spaces/backup" 
DIR="dir_by_project" 
f=":/home/project_in_server" 
OPTIONS="-avr --exclude 'public_html/cms/cache/**' --exclude 'public_html/cms/components/libraries/cmslib/cache/**' --delete" 
eval rsync --delete-excluded -i $OPTIONS [email protected]$f $CURRENT_DIR/xxx/$DIR/files 

¿hay alguna manera que pueda utilizar la variable $CURRENT_DIR sin problemas causados ​​por los espacios?

Respuesta

13
eval rsync --delete-excluded -i $OPTIONS [email protected]$f "\"$CURRENT_DIR/xxx/$DIR/files\"" 

command "some thing" ejecuta el comando con un argumento some thing. Las comillas son analizadas por el shell y los argumentos se configuran como una matriz al ejecutar el comando. El comando verá un argumento como algo sin las comillas.

El comando eval trata sus argumentos más o menos como si estuvieran escritos en el shell. Entonces, si eval command "some thing", bash ejecuta eval con dos argumentos: command y some thing (de nuevo las comillas se comen mientras bash configura la matriz de argumentos). Entonces, eval actúa como si escribieras command some thing en el shell, que no es lo que quieres.

Lo que hice fue simplemente para escapar de las comillas, por lo que bash pasa literalmente "algo" incluyendo las comillas para eval. eval luego actúa como si escribieras command "some thing".

Las comillas externas en mi comando no son estrictamente necesarias, son solo un hábito. También podría usar:

eval rsync --delete-excluded -i $OPTIONS [email protected]$f \"$CURRENT_DIR/xxx/$DIR/files\" 
+0

Está funcionando, pero no sé exactamente por qué? Supongo que tiene que ver con la división de palabras. ¿Podrías por favor elaborar un poco más en tu respuesta? [Editar] Creo que lo tengo ahora. Utilicé eval porque quería $ OPTIONS para ser palabra dividida y eso hizo CURRENT_DIR para ser palabra dividida también? y cuando eval ejecuta eliminar citas primero ... – Cesar

+0

¡Gracias por la aclaración! – Cesar

0

Sé que ya lo he usado, pero, ¿qué pasa con las comillas simples? (este tipo ' ') ?

-1

tiene que escapar en el espacio CURRENT_DIR="/path/with\ spaces/backup" si esto no funciona, a continuación, poner doble barra invertida CURRENT_DIR="/path/with\\ spaces/backup"

+1

esto podría solucionar este problema en particular, pero no es una buena solución en general ... el valor de la variable como se define en la pregunta es correcto y razonable. –

7

El uso de eval es peligroso y debe evitarse siempre que sea posible. En este caso, el problema principal es que está tratando de definir OPCIONES que contienen varias palabras, y las variables bash no manejan esto muy bien. Hay una solución: poner OPCIONES en una matriz, en lugar de una variable simple (y usar comillas dobles alrededor de todas las referencias de variables, para evitar que los espacios se traten como separadores de palabras).

CURRENT_DIR="/path/with spaces/backup" 
DIR="dir_by_project" 
f=":/home/project_in_server" 
OPTIONS=(-avr --exclude 'public_html/cms/cache/**' --exclude 'public_html/cms/components/libraries/cmslib/cache/**' --delete) 
rsync --delete-excluded -i "${OPTIONS[@]}" "[email protected]$f" "$CURRENT_DIR/xxx/$DIR/files" 
+0

+1 para la explicación clara. Solo me pregunto, qué tan portátil es esta solución. Intenté en OS X 10.5 y funcionó, pero ¿funcionará en otros sistemas operativos? ¿Cuál será la versión mínima de bash requerida para que esto funcione? – Cesar

+0

@Cesar: Según [esto] (http://lcorg.blogspot.com/2010/04/new-features-in-bash-version-4x-part-4.html), matrices lineales (el tipo I ' m usando aquí) fueron agregados en bash v2. (Las matrices asociativas son nuevas en bash v4, pero no son necesarias aquí). –

3

estoy de acuerdo con Gordon

Usted no tiene ninguna necesidad de eval en este caso (que no está formando un nombre de variable a partir de variables, o de cualquier otra forma que una expresión sobre la marcha)

Y y usted quiere doblar comilla todos referensces variables que podrían tener espacios que usted desea preservar

Pero Otro buen hábito es siempre variables de refrence con {} ...

"${CURRENT_DIR}" 

en lugar de

$CURRENT_DIR 

Esto elimina cualquier ambigüedad nombre

Cuestiones relacionadas