Tengo un comando almacenado en una variable. Vamos a pretender la variable $i
tiene el valor:
cat -nT index.php |grep 'someregex'
Cuando trato de ejecutar la variable anterior escribiendo $i
falla porque el shell intenta ejecutar la variable completa como un comando. También traté de usar eval($i)
y poniendo $i
en backticks.
¿Cómo puedo hacer que el shell se ejecute? $i
¿Como si fuera una orden? ¿Y por qué no está funcionando igual que?
$i='echo hi'; $i
¿Es porque tuve que hackear las comillas simples? (Porque no puedes anidarlos). Actualmente mi solución es
echo $i > /foo; . /foo
Pero no quiero crear un archivo solo para esto, solo para borrarlo más tarde.
Lo que quiero decir con "pirateé las comillas simples es que hice
$i='cat index.php | grep -P '"'"'MYREGEXHERE'"'"
Respuestas:
Respuesta corta: ver BashAQ # 50: Estoy tratando de poner un comando en una variable, ¡pero los casos complejos siempre fallan! .
Respuesta larga: es debido al orden en que bash analiza la línea de comando. Específicamente, busca cosas como tuberías y redirecciones antes de expandir los valores variables, y no retrocede y vuelve a buscar tuberías, etc. en los valores expandidos. Esencialmente, las variables se sustituyen aproximadamente a la mitad del proceso de análisis, por lo que el valor solo se analiza a la mitad antes de ejecutarse.
Para resolver esto, necesita responder la pregunta de @ slhck: ¿por qué el comando se almacena en una variable en primer lugar? ¿Cuál es el problema real que estás tratando de resolver? Dependiendo del objetivo real, hay una serie de soluciones posibles:
No lo almacene en una variable, solo ejecútelo directamente. El almacenamiento de comandos para su uso posterior es complicado, y si realmente no lo necesita, simplemente no lo haga.
Usa una función en lugar de una variable. Para eso son, después de todo:
La principal desventaja de esto es que no puede crear la función dinámicamente, no puede incluir o excluir condicionalmente el código de la función (aunque la función en sí puede tener elementos condicionales que se seleccionan cuando se ejecuta).
Utilizar
eval
. Esto debe considerarse un último recurso, ya que es fácil tener un comportamiento inesperado. Básicamente, ejecuta el comando a través de otro pase de análisis completo, por lo que todas las canalizaciones, etc. obtienen su significado completo, pero también significa que las partes del comando que pensaste que eran solo datos también se analizarán y tal vez se ejecuten. Los nombres de archivo que contienen metacaracteres de shell (canalización, punto y coma, comillas / apóstrofes, etc.) pueden tener efectos extraños y, a veces, peligrosos. Si usaseval
, al menos doble-comente la cadena, de lo contrario su contenido esencialmente se analiza una vez y media, con resultados aún más extraños.EDITAR: Otro enfoque estándar de almacenar una orden de una variable es usar una matriz en lugar de una variable simple. Esto le permite almacenar un comando con argumentos complejos (por ejemplo, que contienen espacios) sin problemas, pero no almacenará elementos como tuberías y redirecciones. Por lo tanto, el enfoque de matriz no será útil en este caso particular.
fuente
eval
método. Esto me impidió hacer la misma pregunta :). Tengo algo comosudo rsync -aAHXi -n --delete-excluded --exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/lost+found","/mnt/DATA/*","/var/log/*","/var/swap","/var/cache/apt/archives/*.deb"} -e ssh root@piac_wireless:/ /home/mrx/Docs/RPi/backup/piac/piac_usb-root
que no se estaba ejecutando las exclusiones correctamente.eval
para esto, hay demasiadas maneras para que salga mal. Una matriz sería una mejor manera de hacer esto. Ver aquí , aquí y aquí por ejemplo.Esto debería funcionar:
Ten cuidado con eso
eval
presenta posibles vulnerabilidades y situaciones de comportamiento inesperado, por lo que debe usarse, si es que lo hace, con cuidado adicional.fuente
eval
, realmente necesitas usar comillas dobles (eval "$i"
) para evitar efectos extra extra extraños. Por ejemplo, intente esto cona="cat -nT index.php |grep ' .* '"
(es decir, la expresión regular debe hacer coincidir dos espacios con cualquier secuencia de caracteres entre ellos) y ver qué sucede realmente. Para crédito adicional, explique por qué Sucede.Al declarar la variable, no debe usar el signo de dólar como prefijo.
Prueba esto:
fuente