2012-03-27 16 views
55

que estaba usando afirmación "la salida 1" en mis funciones de bash de interrumpir todo el guión y funcionó bien:¿Hay alguna forma de escribir una función bash que anule toda la ejecución, sin importar cómo se llame?

function func() 
{ 
    echo "Goodbye" 
    exit 1 
} 
echo "Function call will abort" 
func 
echo "This will never be printed" 

Pero entonces me di cuenta de que no se haga el trabajo cuando se le llama como:

res=$(func) 

entiendo que he creado un subnivel y "la salida 1" aborta que subnivel y no el principal ....

Pero hay una manera de escribir una función que aborta toda la ejecución, no importa cómo es cal ¿LED? Solo necesito obtener el verdadero valor de retorno (repetido por la función).

Respuesta

64

Lo que podría hacer, es registrar la cáscara de alto nivel para la señal TERM para salir, y después enviar un TERM a la cáscara de nivel superior:

#!/bin/bash 
trap "exit 1" TERM 
export TOP_PID=$$ 

function func() 
{ 
    echo "Goodbye" 
    kill -s TERM $TOP_PID 
} 

echo "Function call will abort" 
echo $(func) 
echo "This will never be printed" 

Por lo tanto, su función envía una señal TERM al nivel superior del shell, que se captura y maneja con el comandante proporcionado d, en este caso, "exit 1".

+1

Estaba pensando en la función C' setsid() ', pero no funciona del mismo modo. Se actualizó para no utilizar el comando 'setsid', ya que nos obligaría a iniciar un nuevo proceso. – FatalError

+2

Trabajos.Cualquier nivel de anidación de funciones, cualquier flujo ... Simplemente funciona. – LiMar

+0

¿Es posible hacer una función de abort() general de esto que sale usando el código del primer argumento, p. 'abort 2' haria la' trampa 'exit 2 "TERM' antes de' kill'? –

26

Puede utilizar set -e cuales exits if a command exits with a non-zero status:

set -e 
func 
set +e 

O tome el valor de retorno:

(func) || exit $? 
+1

Curiosamente, veo una solución. "set-e" en la secuencia de comandos principal causa que cualquier función devuelva 1 (o salga de ella) para cancelar toda la ejecución. Desafortunadamente "set -e" cambia drásticamente todo el comportamiento y no puedo usarlo. – LiMar

+0

Debe usar (()) para realizar comparaciones numéricas. Dentro de [] -gt, -eq, etc. deben usarse. – jordanm

+10

o incluso 'res = $ (func) || exit' –

0

Un proceso hijo no puede obligar al proceso padre para cerrar de manera implícita. Necesitas usar algún tipo de mecanismo de señalización. Opciones podrían incluir un valor especial de retorno, o tal vez de enviar alguna señal con kill, algo así como

function child() { 
    local parent_pid="$1" 
    local other="$2" 
    ... 
    if [[ $failed ]]; then 
     kill -QUIT "$parent_pid" 
    fi 
} 
0

Pero, ¿existe una manera de escribir una función que aborta toda la ejecución, no importa cómo se llama?

Sólo necesito para obtener el valor de retorno real (repetido por la función).

Puede

res=$(func) 
echo $? 
Cuestiones relacionadas