2011-09-17 5 views
21

Genero una variable bash que contiene todos mis argumentos y esos argumentos contienen espacios. Cuando ejecuto un comando con esos argumentos, ej. ls $ args - las comillas no se interpretan correctamente. Aquí hay un ejemplo: también crea y borra los archivos necesarios.bash - variable que contiene múltiples args con comillas

#!/bin/bash 
f1="file n1" 
f2="file n2" 
# create files 
touch "$f1" "$f2" 
# concatenate arguments 
args="\"$f1\" \"$f2\"" 
# Print arguments, then launch 'ls' command 
echo "arguments :" $args 
ls $args 
# delete files 
rm "$f1" "$f2" 

Con eso, tengo algunos errores "No existe el fichero" para "presentar, n1", "Archivo y n2"

+0

http://stackoverflow.com/questions/2005192/how-to-execute-a-bash-command-stored-as-a-string-with -quotes-and-asterisk –

Respuesta

38

usted podría considerar el uso de un array de the args, algo como esto:

args=("$f1" "$f2") 
ls "${args[@]}" 

(El problema que estás golpeando en este momento es que una vez dentro ha ocurrido una terpolación, no hay diferencia entre espacios dentro del mismo nombre y entre archivos).

+3

Esto solo funciona con shells como Bash que admiten matrices. 'eval' descrito a continuación funciona con todas las shells de Unix. –

+0

@ arran-cudbard-bell Bueno, cierto, pero la pregunta menciona varias veces 'bash', por lo que esta solución parece la mejor respuesta. – monnef

+1

No estoy de acuerdo, para mí la sintaxis es extraña y opaca. –

2

Use set para establecer las variables como parámetros de posición; luego se conservarán las citas si se refiere a ellas a través de "$ @" o "$ 1", "$ 2", etc. Asegúrese de usar comillas dobles con sus nombres de variables.

set -- "$f1" "$f2" 
touch "[email protected]" 
ls "[email protected]" 
rm "[email protected]" 
3

Este es probablemente el peor respuesta, pero se puede cambiar IFS. Este es el "separador de campo interno" y es igual a espacio + pestaña + nueva línea por defecto.

#!/bin/sh 
IFS=, 
MAR="-n,my file" 
cat $MAR 

El script anterior se ejecutará cat. El primer argumento será -n (líneas numeradas) y el segundo argumento será my file.

26

Use eval Esto primero evaluará las expansiones y citas y luego ejecutará la cadena resultante como si hubiera sido escrita en el intérprete de comandos.

args="'$f1' '$f2'" 
eval ls $args 

eval a continuación, se ejecuta ls 'file n1' 'file n2'

tenía un problema muy similar, tratando de pasar argumentos en las variables procedentes de /etc/default/ a start_stop_daemon en scripts de inicio.

+1

Downvoted porque 'eval' tiene serios problemas de seguridad; consulte http://stackoverflow.com/a/37573041/120818 para obtener una explicación más detallada, pero básicamente (de http: //mywiki.wooledge.org/BashFAQ/048): "Hace que el código se analice dos veces en lugar de una vez, esto significa que, por ejemplo, si el código tiene referencias variables, el analizador del shell evaluará el contenido de esa variable. contiene un comando de shell, el shell puede ejecutar ese comando, ya sea que lo quieras o no ". – HerbCSO

+3

Es como decir que nunca se debe usar goto en la programación C porque algunos desarrolladores los usan para convertir el código en un nido de ratas. Hay muchos casos en los que eval no presentará problemas de seguridad, realmente no veo que esta sea una crítica válida. –

+2

Estoy de acuerdo con @ ArranCudbard-Bell. Ya estás ejecutando un código potencialmente arbitrario con los argumentos variables. El uso de 'eval' no permite que el código haga más de lo que ya podía bajo las circunstancias. – siride

0

Aquí está mi receta para concat argumentos citados, que se utilizan principalmente para mantener el guión legible. Pero también es cómodo para comentar algunos argumentos con facilidad:

PARAM1="a param with white spaces" 
PARAM2="some other funny param" 
PARAM3="third spaced param" 
#... 

PARAMS=$PARAM1 
PARAMS+='" "' 
PARAMS+=$PARAM2 
PARAMS+='" "' 
PARAMS+=$PARAM3 
#... 

eval command '"'$PARAMS'"' 
Cuestiones relacionadas