Definí una función de shell (llamémosla clock
), que quiero usar como un contenedor para otro comando, similar a la time
función, por ejemplo clock ls -R
.
Mi función de shell realiza algunas tareas y luego termina con exec "$@"
.
Me gustaría que esta función funcione incluso con las funciones integradas de shell, por ejemplo, clock time ls -R
debería generar el resultado de la función time
incorporada, y no el /usr/bin/time
ejecutable. Pero exec
siempre termina ejecutando el comando en su lugar.
¿Cómo puedo hacer que mi función Bash funcione como una envoltura que también acepta incorporaciones de shell como argumentos?
Editar : Acabo de enterarme que time
no es un Bash incorporado, sino una palabra reservada especial relacionada con las tuberías. Todavía estoy interesado en una solución para dispositivos integrados, incluso si no funciona time
, pero una solución más general sería aún mejor.
fuente
exec bash -c \' "$@" \'
. A menos que su comando en el primer parámetro se reconozca como un script de shell, se interpretará como un binario que se ejecutará directamente. Alternativamente, y de manera más simple, simplemente omitaexec
y llame"@"
desde su shell original.Respuestas:
Definiste una función bash. Entonces ya estás en un shell bash cuando invocas esa función. Entonces esa función podría simplemente verse así:
Esa función se puede invocar con bash builtins, palabras especiales reservadas, comandos, otras funciones definidas:
Un alias:
Un bash incorporado:
Otra función:
Un ejecutable:
fuente
$@
yexec $@
, si sé que estoy ejecutando un comando real?exec
, el comando reemplaza el shell. Por lo tanto, ya no hay palabras incorporadas, alias, palabras especiales reservadas, palabras definidas, porque el ejecutable se ejecuta a través de una llamada al sistemaexecve()
. Esa llamada al sistema espera un archivo ejecutable.exec $0
un solo proceso, mientras que$@
todavía tiene dos?$@
tiene el shell en ejecución como padre y el comando como proceso hijo. Pero cuando desea usar builtins, alias, etc., debe preservar el caparazón. O comenzar uno nuevo.La única forma de iniciar un shell incorporado o una palabra clave de shell es iniciar un nuevo shell porque exec "reemplaza el shell con el comando dado". Debe reemplazar su última línea con:
Esto funciona con palabras integradas y palabras reservadas; El principio es el mismo.
fuente
Si el contenedor necesita insertar código antes del comando dado, un alias funcionaría ya que se expanden en una etapa muy temprana:
Los alias se insertan casi literalmente en lugar de la palabra con alias, por lo que el seguimiento
;
es importante, hace que seclock time foo
expanda ado this; do that; time foo
.Puede abusar de esto para crear alias mágicos que incluso eviten las citas.
Para insertar código después de un comando, puede usar el gancho "DEBUG".
Específicamente:
El gancho todavía se ejecuta antes del comando, pero cuando regresa
false
le dice a bash que cancele la ejecución (porque el gancho ya lo ejecutó a través de eval).Como otro ejemplo, puede usar esto para alias
command please
parasudo command
:fuente
La única solución que podría encontrar hasta ahora sería realizar un análisis de caso para distinguir si el primer argumento es un comando, incorporado o una palabra clave, y fallar en el último caso:
Sin embargo, no maneja
time
, por lo que podría haber una solución mejor (y más concisa).fuente