2010-07-05 18 views
5

¿Cómo se escribe una función en bash que ejecuta la orden que se da como argumento, dondefunción Bash mandato que llama da como argumento

  • La orden dada puede ser un alias
  • argumentos deben ser transmitido exactamente como se dio; sin evaluadora podrá hacerse

En otras palabras, cómo escribir un envoltorio funcionan como transparente-como-posible.

El objetivo de la función de envoltura podría ser, por ejemplo, establecer el directorio actual antes y después del comando dado, y/o establecer variables de entorno, o tiempo de duración del comando dado, ... Como un ejemplo simple aquí Tomo una función que solo imprime una línea y luego ejecuta el comando dado.

Un primer intento:

function wrap1 { 
    echo Starting: "[email protected]" 
    "[email protected]" 
} 

se podría utilizar como wrap1 echo hello. Pero el problema es que no puede hacer alias myalias echo y luego llamar al wrap1 myalias hello: no resolvería el alias.

Otro intento usando eval:

function wrap2 { 
    echo Starting: "[email protected]" 
    eval "[email protected]" 
} 

Ahora llamando funciona un alias. Pero el problema es que también evalúa los argumentos. Por ejemplo, wrap2 echo "\\a" imprime solo a en lugar de \a porque los argumentos se evalúan dos veces.

shopt -s expand_aliases parece que tampoco ayuda aquí.

¿Hay alguna manera de evaluar los alias como wrap2, pero aún así transmitir los argumentos directamente como wrap1?

+1

Su primera función es el camino a seguir. Renunciar a manejar correctamente alias. ["Para casi cualquier propósito, las funciones de shell son preferibles a los alias."] (Http://www.gnu.org/software/bash/manual/html_node/Aliases.html#Aliases) –

+0

[lectura obligatoria] (http://mywiki.wooledge.org/BashFAQ/050) –

Respuesta

7

Usted (uh, I) puede usar printf% q para escapar de los argumentos. A primera vista, escaparse con printf y luego hacer eval siempre da el mismo resultado que pasar los argumentos directamente.

wrap() { 
    echo Starting: "[email protected]" 
    eval $(printf "%q " "[email protected]") 
} 
+0

¿Qué es 'command = $ (shift)'? AFAIK 'shift' no escribe en stdout. – Philipp

+0

Pero 'printf"% q "' parece muy prometedor. ¿Esto también funciona para alias indirectos o recursivos? – Philipp

+0

Awtch, el $ (cambio) estaba mal, por supuesto. Arreglado. De hecho, ni siquiera hay razón para hacer una diferencia entre la primera "palabra" (posiblemente el alias) y el resto del comando. –

0

parece ser posible con una doble eval:

eval "eval x=($(alias y | cut -s -d '=' -f 2))" 
# now the array x contains the split expansion of alias y 
"${x[@]}" "${other_args[@]}" 

Así que tal vez su función podría escribirse de la siguiente manera:

wrap() { 
    eval "eval prefix=($(alias $1 | cut -s -d '=' -f 2))" 
    shift 
    "${prefix[@]}" "[email protected]" 
} 

Sin embargo, eval es malo, y el doble eval es el doble del mal y los alias no se expanden en las secuencias de comandos por una razón.

+0

Acepto que generalmente expandir alias en un script no es una buena idea, porque no desea que un alias del usuario cambie lo que hace un comando en un script. Pero eso no es relevante aquí porque el comando en el que intento expandir el alias no es un comando del script, es un comando escrito por el usuario. –

+0

Supongo que quería decir "alias $ 1" en lugar de "alias y" en wrap(). Lo que está haciendo básicamente es volver a implementar la resolución de alias. Espero que se pueda evitar, pero si realmente no hay otra manera, este enfoque podría funcionar, gracias. Para completar la solución, también tendría que tratar con comandos que no son alias, alias que se resuelven en otros alias, alias recursivos, ... Temo que esto se convierta en una especie de bestia. –

+0

Gracias, corregido 'y' →' $ 1'. – Philipp

Cuestiones relacionadas