- Exec sostituisce il programma in esecuzione senza modificare il PID e viene utilizzato insieme a fork() per caricare nuovi eseguibili in C e ambienti Unix.
- Nella shell, exec consente di sostituire la shell stessa o di riconfigurare globalmente i descrittori di file e i reindirizzamenti.
- In Perl, exec e system gestiscono l'esecuzione di comandi esterni con comportamenti diversi, basati su funzioni e moduli come Shell.
- Padroneggiare i descrittori di file ed exec è fondamentale per scrivere script e programmi robusti, controllando attentamente input e output.
Quando si inizia a lavorare seriamente con la riga di comando di GNU/Linux, prima o poi ci si imbatte il misterioso comando exec e le funzioni exec C in Programmi eseguibili UnixAll'inizio il suo comportamento è sconcertante: a volte il copione "Scompare" e interrompe l'esecuzione delle righe; altre volte viene utilizzato per eseguire reindirizzamenti di file insoliti o per avviare processi remoti. Sembra tutto di basso livello, ma è proprio qui che risiede la sua potenza.
In questo articolo decostruiremo questa complessità. Vedrai come exec può avere significati diversi a seconda che si parli della shell, del C o anche di linguaggi come Perl.e come si adatta ad altri pezzi di base come fork(), system, descrittori di file o comandi come findL'idea è che tu finisca con una visione pratica e completa, e che la tua mano non tremi quando vedi un exec in uno script o nel codice sorgente.
Cos'è exec in Unix/Linux: idea generale
Nel kernel Unix, exec è il meccanismo per sostituire il programma attualmente in esecuzione. da uno diverso all'interno dello stesso processo. In altre parole: il processo non muore e ne crea un altro, ma piuttosto la sua "immagine di memoria" viene sostituita con quella di un nuovo programma. Il PID rimane lo stesso, ma il codice e i dati diventano quelli del nuovo eseguibile.
Da un punto di vista pratico, ciò significa che La funzione C exec non restituisce mai un risultato se tutto va bene.La chiamata sostituisce il programma corrente con quello nuovo e verrà visualizzato un valore di ritorno solo se si è verificato un errore (ad esempio, l'eseguibile non esiste o non si dispone delle autorizzazioni).
Questo concetto si riflette in diversi livelli:
- in c: famiglia di funzioni
exec*(execl,execv,execve,execvp, Ecc.). - Nel guscio (Bash, sh, ecc.): comando interno
exec, che può sostituire la shell con un programma o manipolare i descrittori di file. - In linguaggi come Perl: funzione
execche si comporta in modo simile, con sfumature rispetto asystem.
La grazia è che Tutti questi usi condividono la stessa idea di fondo: smettere di eseguire ciò che si stava facendo e, nello stesso processo, passare all'esecuzione di qualcos'altro, o modificare il modo in cui il processo comunica con il mondo esterno attraverso i descrittori.
La famiglia exec in C: sostituzione dell'immagine del processo

En programmazione di sistemi con C in Linux, il La famiglia di funzioni exec è lo strumento standard per caricare un altro programma nel processo corrente.Di solito appare accanto fork(), che è responsabile della creazione del processo figlio.
La definizione generale è che exec sostituisce lo spazio di memoria del processo (codice, dati, stack, ecc.) con quello di un programma diverso. Il sistema operativo prepara questa nuova immagine e salta al suo punto di ingresso come se si fosse avviato da zero, ma riutilizzando lo stesso PID.
Le varianti più comuni sono:
int execl(const char *path, const char *arg, ...);int execv(const char *path, char * const argv[]);int execve(const char *path, char * const argv[], char * const envp[]);int execvp(const char *file, char * const argv[]);
In tutti loro, path è il percorso assoluto verso l'eseguibile, tranne in execvpdove puoi semplicemente passare il nome e cercherà nelle directory definite nella variabile d'ambiente PATHSe l'eseguibile è distribuito come Formato AppImageLa chiamata è ancora valida. Gli argomenti del nuovo programma vengono passati come un elenco di variabili (execl) o come un array (execv e compagnia).
È importante capire che Queste funzioni restituiscono -1 solo se hanno fallito. (Il nuovo programma non è ancora stato eseguito.) Nel caso normale, l'esecuzione non torna al punto della chiamata, perché il codice del processo è già diverso.
Relazione tra fork() ed exec(): creazione di processi ed esecuzione di programmi
In Linux, è consuetudine distinguere chiaramente tra Due idee: creare processi ed eseguire programmiUn processo non è la stessa cosa di un eseguibile, sebbene siano correlati.
Per creare un nuovo processo da uno esistente, si utilizza fork()In parole povere, questa chiamata crea una copia quasi identica del processo padre: stesso codice, stessi stati delle variabili, stessi file aperti, ecc. Il figlio riceve un valore di ritorno. 0 en fork()mentre il padre riceve il PID del figlio. Se qualcosa va storto, entrambi vedranno un -1.
Questa copia non è così rozza come sembra grazie a tecniche come Copy-On-Write (COW)Vengono utilizzati dal sistema operativo per posticipare l'effettiva copia delle pagine di memoria fino a quando uno dei processi non tenta di modificarle. In questo modo si evita di replicare grandi quantità di memoria per poi eliminarle immediatamente se un processo viene chiamato in seguito. exec().
È normale che sia il padre a prendersi cura di creare processi figlio con fork() e delegare loro il vero lavoroIl bambino, una volta creato, esegue exec() per caricare il programma che ci interessa realmente. In questo modo, Il padre può continuare a fare altri figli oppure aspettare che uno finisca. utilizzando wait(), che lo blocca finché il bambino non termina.
Mettere insieme entrambi i pezzi di solito si traduce in patrones come:
- Il padre chiama
fork(). - Nel processo figlio viene richiamata una delle funzioni.
exec*con il programma desiderato, come ad esempiols -l. - Il genitore monitora o sincronizza il completamento del bambino tramite
wait().
Questo modello classico ha alcuni le inefficienze sorgono quando viene realizzata una copia di grandi dimensioni del processo solo per sostituirla immediatamente con exec()</codeDa qui l'importanza di COW e di comprendere chiaramente il ruolo di ogni chiamata nel ciclo di vita del processo.
Il comando exec nella shell: sostituzione della shell e gioco con i descrittori
All'interno di Bash e altre shell, exec È un dispositivo integrato con due grandi utilizzi: sostituisce la shell con un altro comando e modifica la configurazione dei descrittori di file di quella shell.
Il caso più diretto è quando USAS exec seguito da un comando. Ad esempio:
exec wall "Mensaje para todos los usuarios"
qui, la shell che esegue ciò exec cessa di esistere e viene sostituito dal comando wallTutto ciò che segue quella riga nello script non verrà eseguito, perché non c'è letteralmente più alcuna shell in grado di interpretarlo.
Tuttavia, l'uso più interessante nello scripting è solitamente l'altro: utilizzare exec con reindirizzamenti per riconfigurare i descrittori di file globalmente per la sessione o lo script. Ad esempio, è possibile impostare l'output standard su /dev/null:
exec 1>/dev/null
Da quel momento, Qualsiasi comando digitato in quella shell non visualizzerà nulla sullo schermoperché il suo descrittore 1 (stdout) punta a /dev/nullLa cosa interessante è che questo influisce sull'intera shell, non solo su un comando specifico.
È anche possibile aprire un descrittore aggiuntivo associato a un file:
exec 3>>/tmp/salida.log
Così, Il descrittore 3 diventa un canale di uscita per /tmp/salida.logTutto ciò che reindirizzi con >&3 Verrà indirizzato a quel file, mentre il resto dell'output standard rimarrà sullo schermo o dovunque tu l'abbia impostato.
È importante ricordare che la shell mantiene la posizione nel file associata al descrittoreSe si scrive più volte, il puntatore avanza; se si prova a leggere da quel descrittore, si potrebbe essere già alla fine del file e non ottenere nulla. Quando si desidera chiudere il descrittore, è sufficiente:
exec 3>&-
Questo indica alla shell di smettere di usare quel canale. Tricks Sono molto utili per struttura i registri in script complessi o separare diversi tipi di output in file diversi senza dover reindirizzare ogni comando singolarmente.
Esempio avanzato di shell exec: reindirizzamenti globali
Nelle scritture moderatamente elaborate, è comune salvare lo stato originale dei descrittori e quindi reindirizzarli temporaneamente per scaricare l'output in un registro, in un file temporaneo o anche in /dev/null.
Un modello tipico è costituito da prima copia l'output standard a un descrittore ausiliario e quindi reindirizzare l'output standard a un file:
exec 3>&1
exec 1>/tmp/salida.txt
Con questo frammento, Il descrittore 3 punta all'output che aveva in precedenza il descrittore 1. (A terminale (normalmente), quindi il descrittore 1 è connesso al file /tmp/salida.txtDa quel momento in poi, tutto ciò che viene stampato su stdout dai comandi dello script andrà a quel file.
Successivamente, quando non si desidera più continuare a registrare nel file, è possibile ripristinare la situazione iniziale restituendo l'output standard al descrittore 3 e chiudendo quest'ultimo:
exec 1>&3
exec 3>&-
Seguendo queste linee, I comandi visualizzano nuovamente il loro output sullo schermo.e il descrittore ausiliario viene rilasciato. È una soluzione pulita per incapsulare sezioni di uno script che devono essere loggate senza appesantire il resto dei comandi con reindirizzamenti.
È anche possibile reindirizzare l'input della shell standard a un filein modo che tutte le letture di stdin provengono da lì, il che può essere utile in automazioni specifiche o in test in cui si desidera alimentare uno script con dati preregistrati.
Il comando read e la sua relazione con i descrittori
All'interno dell'ecosistema della shell, read È il comando responsabile della lettura dall'input standard e della memorizzazione del risultato nelle variabiliPer impostazione predefinita, continua a leggere finché non trova un'interruzione di riga, ma il suo comportamento può essere ottimizzato tramite diverse opzioni.
la via più facile è:
read MIVAR
Con questo, La stringa digitata sulla tastiera finché non si preme Invio viene salvata in MIVARÈ abbastanza comune aggiungere l'opzione -r in modo che le barre rovesciate non vengano interpretate come caratteri di escape:
read -r MIVAR
Ci sono opzioni particolarmente utili come -pche consente di visualizzare un testo di richiesta e -sche impedisce che ciò che digiti venga riprodotto sullo schermoQuesto è esattamente ciò che si usa quando si desidera richiedere una password all'interno di uno script:
read -s -p "Contraseña: " PASSWD
In questo caso, Non vedrai i caratteri che digiti, proprio come quando corri su o sudo. Anche read È strettamente connesso alla variabile speciale. IFS, che definisce quali caratteri sono considerati separatori di campo (per impostazione predefinita tabulazione, spazio e interruzione di riga).
Se fai qualcosa del tipo:
IFS="-"; read A B C
L'ordine interpreterà il carattere trattino come separatoreDistribuendo i campi letti tra le variabili A, B e C. Se ci sono più variabili che campi, questi ultimi saranno vuoti; se ci sono più campi che variabili, L'ultimo accumulerà tutti i rimanenti..
Ed ovviamente, Tutto questo è combinato con i reindirizzamenti che configuri con exec: se hai reindirizzato stdin in un file, read Recupererà i dati da lì anziché dalla tastiera. Questa flessibilità è uno dei pilastri degli script shell ben progettati.
exec in Perl: differenze con il sistema e utilizzo avanzato
In Perl, il concetto di exec È molto in linea con il comportamento in C e nella shell.Questo viene utilizzato per sostituire il processo corrente con un altro programma. Tuttavia, Perl offre anche systemche spesso viene confuso con exec anche se non fanno la stessa cosa.
La funzione system Avvia un comando esterno e attende che venga completato, restituendo il controllo allo script.. Anziché, exec Sostituisce completamente il processo Perl con il programma chiamato e non ritorna allo scriptsalvo in caso di errore. Un esempio molto semplice sarebbe:
exec 'cat -n /etc/passwd';
die "no se pudo ejecutar cat: $!";
Si la chiamata a exec Se avrà successo, non verrà mai eseguito. dieperché l'interprete Perl sarà stato sostituito dal binario catSe fallisce (ad esempio perché non esiste) cat), quindi viene eseguito die visualizzando il messaggio di errore e il valore di $!.
Un dettaglio molto utile è che, proprio come con system, puoi evocare exec con un elenco di argomenti per impedire l'interpretazione dei metacaratteri della shell. Ad esempio:
exec '/bin/echo', 'Los argumentos son: ', @ARGV;
Se esegui lo script in questo modo:
./exec.pl 'uno' '| ls ' '| who > quien'
Lo vedrai gli argomenti che includono | o i reindirizzamenti non attivano la shellma vengono trasferiti così come sono /bin/echoL'output sarebbe più o meno questo:
Los argumentos son: uno | ls | who > quien
Vale a dire, nessun comando è stato effettivamente eseguito, sono stati mostrati solo i testi.
Utilizzare exec in Perl per preparare un ambiente di runtime
Oltre ai semplici esempi, Perl si presta alla creazione di script che preparano in modo sofisticato l'ambiente di lavoro prima di eseguire un altro programmaUn caso tipico è quando si avviano attività su macchine remote tramite SSH e si desidera ricreare un certo contesto del processo locale.
Un approccio comune è quello di avere una subroutine che crea dinamicamente uno script temporaneo e poi lo esegueIn quello script, puoi impostare la directory di lavoro, le variabili di ambiente o il comportamento dei segnali e infine utilizzare system o exec a seconda che si voglia tornare all'imballaggio oppure no.
Ad esempio, può essere conservato in un catena multilinea un piccolo programma che:
- Passare alla directory originale da cui è stato richiamato lo script principale.
- Ripristinare le variabili di ambiente da un elenco serializzato.
- Eseguire il comando effettivo con
system, controllandone lo stato di uscita. - Elimina lo script temporaneo e termina esplicitamente con
exit(0).
Prima di salvare il programma nel file temporaneo, I marcatori di testo vengono sostituiti (la directory, il comando da eseguire, il nome dello script, ecc.) con i loro valori effettivi. Con questa tecnica, è possibile incapsulare tutta la logica di preparazione dell'ambiente e disporre di un singolo punto di ingresso che semplicemente "incapsula" qualsiasi esecuzione remota.
Questo tipo di soluzione sfrutta appieno La capacità di Perl di manipolare stringhe, file e processie si adatta molto bene alle funzioni exec y system quando sono necessari comportamenti molto specifici nei sistemi distribuiti.
Modulo Shell di Perl e chiamata implicita dei comandi
Un altro aspetto curioso legato a L'esecuzione di comandi esterni in Perl è il modulo ShellQuesto modulo consente di chiamare i programmi di sistema come se fossero funzioni Perl, grazie all'utilizzo di AUTOLOAD.
Immagina di caricare il modulo in questo modo:
use Shell qw(echo cat ps cp);
Da quel momento, quando scrivi qualcosa come:
$foo = echo("howdy", "funny", "world");
Quello che succede sotto è che Perl non riesce a trovare una subroutine chiamata echo e spara AUTOLOAD del moduloQuesto meccanismo:
- Identificare il nome del comando a partire dal nome completo della subroutine (
Shell::echo). - Costruire dinamicamente una funzione reale che eseguirà quel comando di sistema.
- Inoltra la chiamata alla nuova funzionalità, trasmettendo le argomentazioni ricevute.
Se si esamina l'esecuzione con il debugger Perl, si vedrà come Gli argomenti sono organizzati in @_ e viene costruito il comando da lanciare.Il risultato della corsa echo Viene raccolto e conservato in $foo, affinché:
print $foo;
Mostrerà qualcosa dello stile howdy funny world con il formato che genera echo del sistemaQuesto approccio è comodo, ma non bisogna abusarne perché può rendere più difficile la leggibilità del codice e la gestione degli errori.
Il comando exec nella shell come strumento di reindirizzamento avanzato
Come abbiamo visto, il comando exec Nel guscio, non viene utilizzato solo per sostituire il guscio.Viene invece spesso utilizzato per aprire, chiudere o duplicare i descrittori di file. Questa capacità consente la creazione di pattern molto efficaci negli script.
Ad esempio, potresti voler reindirizzare permanentemente l'output dell'intero script a un file di registro senza dover fare >>log.txt su ogni riga. Qualcosa del tipo:
exec >/var/log/mi_script.log 2>&1
Con questo, Sia l'output standard che l'output di errore andranno allo stesso file Fin dall'inizio dello script. Da quel momento in poi, qualsiasi comando fallito lascerà una traccia nel registro senza ingombrare il terminale.
In altri casi, potresti essere interessato a associare descrittori specifici ai file temporanei per salvare i dati che elaborerai in seguito. Chiudendo quei descrittori con exec n>&-Si liberano risorse e si evitano fughe di dati tra i gestori.
È vero che questo tipo di costruzione non si riscontra negli script di base, ma Quando si inizia a scrivere, le utilità amministrative serie diventano quasi indispensabili. per controllare correttamente cosa viene visualizzato sullo schermo, cosa viene salvato e come sono strutturate le informazioni.
In breve, per padroneggiare exec come strumento di reindirizzamento avanzato ti dà un livello di controllo sull'I/O degli script della shell che fa la differenza tra script "fatti in casa" e strumenti di produzione robusti.
Alla fine di tutto questo viaggio, l'idea chiave è che exec, sia in C, nella shell o in Perl, ruota sempre attorno a due assi: la sostituzione del programma in esecuzione e la gestione accurata di input e output.Capire come si combinano con fork(), system, read o moduli come Shell Consente di progettare soluzioni più pulite, più efficienti e più sicure, sia per l'avvio di processi remoti, l'incapsulamento di ambienti di esecuzione complessi o semplicemente la scrittura di script che fanno esattamente ciò che si desidera, senza sorprese.
Scrittore appassionato del mondo dei byte e della tecnologia in generale. Adoro condividere le mie conoscenze attraverso la scrittura, ed è quello che farò in questo blog, mostrarti tutte le cose più interessanti su gadget, software, hardware, tendenze tecnologiche e altro ancora. Il mio obiettivo è aiutarti a navigare nel mondo digitale in modo semplice e divertente.
