Me gustaría almacenar un comando para usar en un período posterior en una variable (no la salida del comando, sino el comando en sí)
Tengo un script simple de la siguiente manera:
command="ls";
echo "Command: $command"; #Output is: Command: ls
b=`$command`;
echo $b; #Output is: public_html REV test... (command worked successfully)
Sin embargo, cuando intento algo un poco más complicado, falla. Por ejemplo, si hago
command="ls | grep -c '^'";
La salida es:
Command: ls | grep -c '^'
ls: cannot access |: No such file or directory
ls: cannot access grep: No such file or directory
ls: cannot access '^': No such file or directory
¿Alguna idea de cómo podría almacenar tal comando (con tuberías / múltiples comandos) en una variable para su uso posterior?
Respuestas:
Utilice eval:
fuente
backticks
. y = $ (eval $ x) mywiki.wooledge.org/BashFAQ/082eval
es una práctica aceptable solo si confía en el contenido de sus variables. Si está ejecutando, digamos,x="ls $name | wc"
(o inclusox="ls '$name' | wc"
), entonces este código es una vía rápida para las vulnerabilidades de inyección o escalada de privilegios si esa variable puede ser configurada por alguien con menos privilegios. (¿Iterando sobre todos los subdirectorios en/tmp
, por ejemplo? Será mejor que confíe en cada usuario del sistema para que no haga uno llamado$'/tmp/evil-$(rm -rf $HOME)\'$(rm -rf $HOME)\'/'
).eval
es un gran imán de errores que nunca debe recomendarse sin una advertencia sobre el riesgo de un comportamiento de análisis inesperado (incluso sin cadenas maliciosas, como en el ejemplo de @ CharlesDuffy). Por ejemplo, intentex='echo $(( 6 * 7 ))'
y luegoeval $x
. Es de esperar que imprima "42", pero probablemente no lo hará. ¿Puedes explicar por qué no funciona? ¿Puedes explicar por qué dije "probablemente"? Si las respuestas a esas preguntas no son obvias para usted, nunca debe tocareval
.set -x
antemano para registrar la ejecución de los comandos, lo que hará que sea más fácil ver lo que está sucediendo.¡No lo use
eval
! Tiene un gran riesgo de introducir ejecución de código arbitrario.BashFAQ-50 : estoy tratando de poner un comando en una variable, pero los casos complejos siempre fallan.
Colóquelo en una matriz y expanda todas las palabras con comillas dobles
"${arr[@]}"
para no permitir queIFS
las palabras se dividan debido a la división de palabras .y ver el contenido de la matriz en su interior. Le
declare -p
permite ver el contenido de la matriz dentro con cada parámetro de comando en índices separados. Si uno de esos argumentos contiene espacios, citar adentro mientras se agrega a la matriz evitará que se divida debido a la división de palabras.y ejecutar los comandos como
(o) usar una
bash
función para ejecutar el comando,y llamar a la función como
POSIX
sh
no tiene matrices, por lo que lo más cerca que puede acercarse es crear una lista de elementos en los parámetros posicionales. Aquí hay unash
forma POSIX de ejecutar un programa de correoTenga en cuenta que este enfoque solo puede manejar comandos simples sin redirecciones. No puede manejar redirecciones, canalizaciones, bucles for / while, declaraciones if, etc.
Otro caso de uso común es cuando se ejecuta
curl
con múltiples campos de encabezado y carga útil. Siempre puede definir argumentos como a continuación e invocarcurl
en el contenido de la matriz expandidaOtro ejemplo,
ahora que las variables están definidas, use una matriz para almacenar sus argumentos de comando
y ahora haz una expansión cotizada adecuada
fuente
Command=('echo aaa | grep a')
y"${Command[@]}"
, esperando que se ejecute literalmente el comandoecho aaa | grep a
. No es así. Me pregunto si hay una forma segura de reemplazareval
, pero parece que cada solución que tenga la misma fuerza queeval
podría ser peligrosa. ¿No es así?Command() { echo aaa | grep a; }
- después de lo cual puede ejecutarCommand
, oresult=$(Command)
, o similar.Con este método, el comando se evalúa inmediatamente y se almacena su valor de retorno.
Lo mismo con la comilla invertida
Usar eval en el
$(...)
no hará que se evalúe más tardeUsando eval, se evalúa cuando
eval
se usaEn el ejemplo anterior, si necesita ejecutar un comando con argumentos, colóquelos en la cadena que está almacenando
Para los scripts de bash esto rara vez es relevante, pero una última nota. Tenga cuidado con
eval
. Evalúe solo las cadenas que controla, nunca las que provengan de un usuario que no sea de confianza o que se generen a partir de la entrada de un usuario que no sea de confianza.fuente
eval $stored_date
puede ser suficiente cuandostored_date
solo contienedate
, peroeval "$stored_date"
es mucho más confiable. Ejecutestr=$'printf \' * %s\\n\' *'; eval "$str"
con y sin las comillas alrededor de la final"$str"
como ejemplo. :)Para bash, almacena tu comando de esta manera:
Ejecute su comando así:
fuente
Probé varios métodos diferentes:
Salida:
Como puede ver, solo el tercero
"$@"
dio el resultado correcto.fuente
Tenga cuidado al registrar un pedido con:
X=$(Command)
Este todavía se ejecuta incluso antes de ser llamado. Para comprobar y confirmar esto, puede hacer:
fuente
fuente
No es necesario almacenar comandos en variables, incluso si necesita usarlo más tarde. simplemente ejecútelo como de costumbre. Si almacena en variable, necesitaría algún tipo de
eval
declaración o invocar algún proceso de shell innecesario para "ejecutar su variable".fuente
var='*.txt'; find . -name "$var"