¿Cuál es la forma correcta de llamar a algún comando almacenado en una variable?
¿Hay alguna diferencia entre 1 y 2?
#!/bin/sh
cmd="ls -la $APPROOTDIR | grep exception"
#1
$cmd
#2
eval "$cmd"
¿Cuál es la forma correcta de llamar a algún comando almacenado en una variable?
¿Hay alguna diferencia entre 1 y 2?
#!/bin/sh
cmd="ls -la $APPROOTDIR | grep exception"
#1
$cmd
#2
eval "$cmd"
Respuestas:
Los shells de Unix operan una serie de transformaciones en cada línea de entrada antes de ejecutarlas. Para la mayoría de los shells, se parece a esto (tomado de la página de bash
manual):
El uso $cmd
directo lo reemplaza por su comando durante la fase de expansión de parámetros, y luego se somete a todas las transformaciones siguientes.
El uso eval "$cmd"
no hace nada hasta la fase de eliminación de la cotización, donde $cmd
se devuelve como está y se pasa como un parámetro a eval
, cuya función es ejecutar toda la cadena nuevamente antes de ejecutar.
Entonces, básicamente, son iguales en la mayoría de los casos y difieren cuando su comando hace uso de los pasos de transformación hasta la expansión de parámetros. Por ejemplo, usando la expansión de llaves:
$ cmd="echo foo{bar,baz}"
$ $cmd
foo{bar,baz}
$ eval "$cmd"
foobar foobaz
eval "$cmd"
sin escribir eval
? $($cmd)
? ${$cmd}
?
eval
operación analiza los datos como sintaxis; por lo tanto, es muy sensible a la seguridad, y hacerlo implícitamente sería de muy mala forma.
Si simplemente lo hacemos eval $cmd
cuando lo hacemos cmd="ls -l"
(de forma interactiva y en un script) obtenemos el resultado deseado. En su caso, tiene una tubería con un grep sin un patrón, por lo que la parte grep fallará con un mensaje de error. Solo $cmd
generará un mensaje de "comando no encontrado" (o algo así). Así que intente usar eval y use un comando terminado, no uno que genere un mensaje de error.
$cmd
simplemente reemplazaría la variable con su valor para ser ejecutado en la línea de comando.
eval "$cmd"
hace expansión de variables y sustitución de comandos antes de ejecutar el valor resultante en la línea de comandos
El segundo método es útil cuando desea ejecutar comandos que no son flexibles, por ejemplo.
for i in {$a..$b}
El bucle de formato no funcionará porque no permite variables.
En este caso, una tubería a bash o eval es una solución.
Probado en Mac OSX 10.6.8, Bash 3.2.48
Creo que deberías poner
`
(comillas invertidas) símbolos alrededor de su variable.