2014-06-08 12 views
10

Mi piacerebbe utilizzare una trappola EXIT trappola e utilizzare exec per evitare di generare un nuovo processo. È possibile?Come posso ottenere una trappola EXIT bash quando eseguo un altro binario?

Cioè,

#!/bin/bash 
touch $0.$$ 
trap "rm -v $0.$$" EXIT 
/bin/echo Hello 

rimuove il file temporaneo $0.$$ usando EXIT trappola di bash mentre

#!/bin/bash 
touch $0.$$ 
trap "rm -v $0.$$" EXIT 
exec /bin/echo Hello 

mai "fuochi" trappola (nessun messaggio da rm, il file $0.$$ esiste dopo il completamento).

Ovviamente, ha senso che la trappola non possa sparare poiché bash non ha più il controllo dopo lo exec. C'è un modo per farlo funzionare e utilizzare exec? Questo è certamente per curiosità più che per questioni pratiche.

risposta

12

Generalmente, n. Questo non è possibile per la ragione che hai menzionato.

Questa è una risposta noiosa però. Diamo un'occhiata alle nostre opzioni per soluzioni alternative:

Se ci preoccupiamo di più sulla semantica exec e meno su come avviare processi multipli, possiamo per gli eseguibili arbitrari fare:

{ while kill -0 $$; do sleep 5; done; rm "$0.$$"; } & 
exec ./file 

che exec il file e hanno un altro polling processo e facendo pulizia quando ha finito.

Se vogliamo evitare forchette e quello che stiamo eseguendo è un altro script di shell, possiamo fare

exec bash --rcfile <(echo 'trap "..." exit') -i ./file 

al exec il file e fare la pulizia dopo (finché lo script non fa exec o scavalcare la trappola), senza avviare un nuovo processo. source ing invece di exec ing avrà più o meno lo stesso effetto:

trap "..." exit 
source ./file 

Se vogliamo ottenere davvero hacky, possiamo usare LD_PRELOAD per ignorare exit(3) ed eseguire un comando di nostra scelta:

#include <stdlib.h> 

void exit(int c) { 
    char* cmd = getenv("EXIT"); 
    char *argv[] = { "bash", "-c", cmd, NULL }; 
    char *envp[] = { NULL }; 
    execvpe("bash", argv, envp); 
} 

Possiamo compilarlo come una libreria:

$ gcc -shared -fPIC foo.c -o libfoo.so 

e quindi precaricare in executa arbitrario, collegato dinamicamente bles:

$ LD_PRELOAD=./libfoo.so EXIT='echo "This is a hack"' ls *foo* 
foo.c libfoo.so 
This is a hack 

Questi hack sono divertenti, ma raramente necessari nel mondo reale. La soluzione più semplice, migliore e più canonica è semplicemente non exec.

Problemi correlati