- Exec zamjenjuje pokrenuti program bez promjene PID-a i koristi se zajedno s fork() za učitavanje novih izvršnih datoteka u C i okruženjima. Unix.
- U ljusci, exec vam omogućava da zamijenite samu ljusku ili globalno rekonfigurišete deskriptore datoteka i preusmjeravanja.
- U Perlu, exec i system upravljaju izvršavanjem naredbi naredbe vanjski s različitim ponašanjima, oslanjajući se na funkcije i module kao što je Shell.
- Savladavanje exec i deskriptora datoteka ključno je za pisanje robusnih skripti i programa, temeljno kontrolirajući ulaz i izlaz.
Kada ozbiljno počnete raditi s GNU/Linux komandnom linijom, prije ili kasnije ćete naići na misterioznu naredbu `exec` i C `exec` funkcije u Unix izvršnim programima . U početku, njihovo ponašanje je zbunjujuće: ponekad skripta "nestane" i prestane izvršavati linije, drugi put se koristi za izvođenje neobičnih preusmjeravanja datoteka ili za pokretanje udaljenih procesa. Sve to zvuči vrlo nisko, ali upravo u tome leži njihova snaga.
U ovom članku ćemo razotkriti tu složenost. Vidjet ćete kako Naredba exec može značiti različite stvari ovisno o tome govorimo li o shell-u, C-u ili čak jezicima poput Perla.i kako se uklapa s drugim osnovnim komadima poput fork(), system, deskriptori datoteka ili naredbe kao što su findIdeja je da na kraju dobijete praktičnu i sveobuhvatnu viziju i da vam ruka neće drhtati kada vidite exec u skripti ili u izvornom kodu.
Šta je exec u Unixu/Linuxu: opšta ideja
U Unix kernelu, `exec` je mehanizam za zamjenu trenutno pokrenutog programa drugim unutar istog procesa. Drugim riječima, proces se ne završava i ne kreira novi; umjesto toga, njegova memorijska slika se zamjenjuje sa slikom novog programa. ID procesa (PID) ostaje isti, ali kod i podaci postaju isti kao kod novog izvršnog programa.
Sa praktične tačke gledišta, ovo znači da C `exec` funkcija nikada ne vraća vrijednost ako sve prođe dobro . Poziv zamjenjuje trenutni program novim, a povratnu vrijednost ćete vidjeti samo ako je došlo do greške (na primjer, ako izvršna datoteka ne postoji ili nemate dozvole).
Ovaj koncept se ogleda na nekoliko nivoa :
- u Cporodica funkcija
exec*(execl,execv,execve,execvp, Itd). - U ljusci (Bash, sh, itd.): interna komanda
exec, koji može zamijeniti ljusku programom ili manipulirati deskriptorima datoteka. - U jezicima poput Perla: funkcija
execkoji se ponaša slično, sa nijansama u poređenju sasystem.
Ljepota toga je u tome što sve ove upotrebe dijele istu osnovnu ideju : zaustaviti izvršavanje onoga što se radilo i, u istom procesu, preći na izvršavanje nečeg drugog ili modificirati način na koji taj proces komunicira s vanjskim svijetom putem deskriptora.
Familija exec kodova u C-u: zamjena slike procesa

En programiranje sistema sa C u Linux, u Familija funkcija exec je standardni alat za učitavanje drugog programa u trenutni proces.Obično se pojavljuje pored fork(), koji je odgovoran za kreiranje podređenog procesa.
Opšta definicija je da `exec` zamjenjuje memorijski prostor procesa (kod, podatke, stek, itd.) prostorom drugog programa. Operativni sistem priprema ovu novu sliku i prelazi na svoju ulaznu tačku kao da se pokrenuo od nule, ali ponovo koristeći isti PID.
Najčešće varijacije su:
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[]);
U svima njima, path je apsolutna putanja do izvršne datoteke, osim u execvpgdje jednostavno možete proslijediti ime i pretraživat će direktorije definirane u varijabli okruženja PATHAko se izvršna datoteka distribuira kao AppImage formatPoziv se i dalje primjenjuje. Argumenti novog programa se prenose kao lista varijabli (execl) ili kao niz (execv i kompanija).
Važno je razumjeti da ove funkcije vraćaju -1 samo ako nisu uspjele (novi program nije izvršen). U normalnom slučaju, izvršenje se ne vraća na tačku poziva jer je kod procesa već drugačiji.
Veza između fork() i exec(): kreiranje procesa i izvršavanje programa
U Linuxu je uobičajeno jasno razlikovati dva koncepta: kreiranje procesa i pokretanje programa . Proces nije isto što i izvršna datoteka, iako su povezani.
Da biste kreirali novi proces iz postojećeg, koristite fork()Ovaj poziv, jednostavno rečeno, pravi gotovo identičnu kopiju roditeljskog procesa: isti kod, ista stanja varijabli, iste otvorene datoteke itd. Dijete prima povratnu vrijednost. 0 en fork()dok otac prima sinov PID. Ako nešto pođe po zlu, oboje će vidjeti -1.
Ova kopija nije tako gruba kao što zvuči zahvaljujući tehnikama kao što su Kopiranje prilikom pisanja (COW)Operativni sistem ih koristi za odgađanje stvarnog kopiranja memorijskih stranica dok jedan od procesa ne pokuša da ih modificira. Ovo izbjegava repliciranje velikih količina memorije samo da bi se one odmah odbacile ako se kasnije pozove neki proces. exec().
Uobičajeno je da se otac brine o kreirajte podprocese sa fork() i delegirajte pravi posao njimaDijete, jednom stvoreno, izvršava exec() da učitamo program koji nas zapravo zanima. Na ovaj način, Otac može nastaviti stvarati još djece ili čekati da jedno završi. koristeći wait(), što ga blokira dok dijete ne završi.
Kombinacija oba dijela često rezultira uzorcima poput:
- Otac zove
fork(). - U podređenom procesu, poziva se jedna od funkcija.
exec*sa željenim programom, kao što jels -l. - Roditelj prati ili sinhronizuje djetetovo završavanje tako što
wait().
Ovaj klasični model ima nekoliko Neefikasnosti nastaju kada se napravi velika kopija procesa samo da bi se odmah zamijenila exec()</codeOtuda je važnost COW-a i jasnog razumijevanja uloge svakog poziva u životnom ciklusu procesa.
Komanda exec u ljusci: zamjena ljuske i igranje s deskriptorima
Unutar Bash-a i drugih shell-ova, exec To je ugrađeni uređaj s dvije odlične upotrebe: zamijenite ljusku drugom naredbom i modificirajte konfiguraciju deskriptora datoteka te ljuske.
Najdirektniji slučaj je kada ti koristiš exec nakon čega slijedi naredba. Na primjer:
exec wall "Mensaje para todos los usuarios"
Evo, ljuska koja to izvršava exec prestaje postojati i zamjenjuje se naredbom wallSve što dolazi nakon te linije u skripti neće biti izvršeno, jer doslovno ne postoji ljuska koja bi to interpretirala.
Međutim, najzanimljivija upotreba u skriptiranju je obično druga: usar exec s preusmjeravanjima za rekonfiguraciju deskriptora datoteka globalno za sesiju ili skriptu. Na primjer, standardni izlaz može ići na /dev/null:
exec 1>/dev/null
Od tada, Bilo koja komanda koju unesete u toj ljusci neće prikazati ništa na ekranu.jer njegov deskriptor 1 (stdout) pokazuje na /dev/nullMoćna stvar je što ovo utiče na cijelu ljusku, ne samo na određenu komandu.
Također možete otvoriti dodatni deskriptor povezan s datotekom:
exec 3>>/tmp/salida.log
Na ovaj način, Deskriptor 3 postaje izlazni kanal za /tmp/salida.logSve što preusmjeravate >&3 Ići će u tu datoteku, dok će ostatak standardnog izlaza ostati na ekranu ili gdje god ste ga podesili.
Važno je zapamtiti da shell održava poziciju u datoteci povezanu s deskriptorom . Ako pišete više puta, pokazivač se pomiče; ako zatim pokušate čitati iz tog deskriptora, možda ste već na kraju datoteke i ne dobijete ništa. Kada želite zatvoriti deskriptor, jednostavno:
exec 3>&-
Ovo govori ljusci da prestane koristiti taj kanal. Ovi trikovi su vrlo korisni za strukturiranje logova u složenim skriptama ili odvajanje različitih tipova izlaza u različite datoteke bez potrebe za preusmjeravanjem svake naredbe pojedinačno.
Napredni primjer shell exec-a: globalna preusmjeravanja
U umjereno složenim pismima, uobičajeno je sačuvati originalno stanje deskriptora, a zatim ih privremeno preusmjeriti zapisati izlaz u dnevnik, privremenu datoteku ili čak u /dev/null.
Tipičan obrazac uključuje prvo kopiranje standardnog izlaza u pomoćni deskriptor, a zatim preusmjeravanje standardnog izlaza u datoteku:
exec 3>&1
exec 1>/tmp/salida.txt
S ovim fragmentom, Deskriptor 3 ukazuje na izlaz koji je deskriptor 1 prethodno imao. (u terminal (normalno), a zatim se deskriptor 1 povezuje sa datotekom /tmp/salida.txtOd tada nadalje, sve što se ispiše na stdout iz naredbi skripte ići će u tu datoteku.
Kasnije, kada više ne želite da se logujete u datoteku, možete vratiti početno stanje vraćanjem standardnog izlaza u deskriptor 3 i zatvaranjem potonjeg:
exec 1>&3
exec 3>&-
Nakon ovih linija, naredbe se vraćaju na prikazivanje svog izlaza na ekranu , a pomoćni deskriptor se oslobađa. Ovo je čisto rješenje za enkapsuliranje dijelova skripte koji se trebaju zapisivati bez zatrpavanja ostatka naredbi preusmjeravanjima.
Moguće je i preusmjeri standardni ulaz shell-a u datotekutako da sva očitanja od stdin dolaze odatle, što može biti korisno u određenim automatizacijama ili u testovima gdje želite da skriptu date unaprijed snimljene podatke.
Naredba za čitanje i njen odnos s deskriptorima
Unutar ekosistema ljuske, read To je naredba odgovorna za čitanje sa standardnog ulaza i pohranjivanje rezultata u varijablePodrazumevano, čita dok ne pronađe prekid reda, ali njegovo ponašanje se može fino podesiti pomoću nekoliko opcija.
Najjednostavniji način je:
read MIVAR
S ovim, Niz znakova koji kucate na tastaturi dok ne pritisnete Enter se čuva u MIVARSasvim je uobičajeno dodati opciju -r tako da se obrnute kose crte ne interpretiraju kao escape znakovi:
read -r MIVAR
Postoje posebno korisne opcije kao što su -pšto vam omogućava prikaz tekstualnog upita, y -sšto sprečava da se ono što kucate odražava na ekranuTo je upravo ono što koristite kada želite zatražiti lozinku unutar skripte:
read -s -p "Contraseña: " PASSWD
U ovom slučaju, Nećete vidjeti znakove koje unosite, baš kao kada pokrenete su o sudo. Takođe, read To je usko povezano sa specijalnom varijablom. IFS, koji definira koji se znakovi smatraju separatorima polja (podrazumevano tabulator, razmak i prelom reda).
Ako uradite nešto poput:
IFS="-"; read A B C
Naredba će interpretirati crticu kao separator , raspoređujući polja za čitanje među varijablama A, B i C. Ako ima više varijabli nego polja, posljednja će biti prazna; ako ima više polja nego varijabli, posljednje će akumulirati sva preostala.
I naravno, Sve ovo je kombinovano sa preusmjeravanjima koja konfigurišete pomoću exec: ako ste preusmjerili stdin u datoteku, read Podatke će preuzimati odatle umjesto s tastature. Ta fleksibilnost je jedan od temelja dobro dizajniranih shell skripti.
exec u Perlu: razlike u odnosu na sistem i napredna upotreba
U Perlu, koncept exec To je u velikoj mjeri u skladu s ponašanjem u C-u i u shell-u.Ovo se koristi za zamjenu trenutnog procesa drugim programom. Međutim, Perl također nudi systemšto se često miješa sa exec čak i ako ne rade istu stvar.
Funkcija system Pokreće vanjsku naredbu i čeka da se završi, vraćajući kontrolu skripti.. Umjesto toga, exec Potpuno zamjenjuje Perl proces pozvanim programom i ne vraća se u skriptu.osim u slučaju greške. Vrlo jednostavan primjer bi bio:
exec 'cat -n /etc/passwd';
die "no se pudo ejecutar cat: $!";
Si poziv na exec Ako uspije, nikada neće biti izvršeno. diejer će Perl interpreter biti zamijenjen binarnim catAko ne uspije (na primjer, zato što ne postoji) cat), zatim se izvršava die prikaz poruke o grešci i vrijednosti $!.
Jedan veoma koristan detalj je da, baš kao i sa system, možete prizvati exec sa listom argumenata za sprečavanje interpretacije shell metakaraktera. Na primjer:
exec '/bin/echo', 'Los argumentos son: ', @ARGV;
Ako pokrenete taj skript ovako:
./exec.pl 'uno' '| ls ' '| who > quien'
Vidjet ćete to argumenti koji uključuju | ili preusmjeravanja ne aktiviraju ljuskuali se prenose kakvi jesu /bin/echoIzlaz bi bio nešto ovako:
Los argumentos son: uno | ls | who > quien
Drugim riječima, nijedna komanda zapravo nije izvršena ; prikazani su samo tekstovi.
Koristite exec u Perlu za pripremu okruženja za izvršavanje
Pored jednostavnih primjera, Perl se lako koristi za izradu skripti koje sofisticirano pripremaju radno okruženje prije pokretanja drugog programa . Tipičan slučaj je kada ćete pokretati zadatke na udaljenim mašinama putem SSH- a i želite ponovo kreirati određene kontekste lokalnog procesa.
Uobičajeni pristup je imati potprogram koji dinamički gradi privremeni skript, a zatim ga izvršavaU tom skriptu možete postaviti radni direktorij, varijable okruženja ili ponašanje signala i na kraju koristiti system o exec u zavisnosti od toga da li želimo da se vratimo na ambalažu ili ne.
Na primjer, mali program se može pohraniti u višelinijski niz koji:
- Promjena u originalni direktorij iz kojeg je pozvan glavni skript.
- Vrati varijable okruženja iz serijalizirane liste.
- Izvršite stvarnu komandu con
system, provjeravajući njegov izlazni status. - Izbriši privremenu skriptu i završava eksplicitno sa
exit(0).
Prije spremanja programa u privremenu datoteku, rezervirana mjesta za tekst (direktorij, naredba za izvršavanje, naziv skripte itd.) zamjenjuju se stvarnim vrijednostima. Ova tehnika vam omogućava da enkapsulirate svu logiku pripreme okruženja i imate jednu ulaznu tačku koja jednostavno "obavija" svako udaljeno izvršavanje.
Ova vrsta rješenja u potpunosti iskorištava Perlova sposobnost manipulisanja stringovima, datotekama i procesimai odlično se uklapa u funkcije exec y system kada su potrebna vrlo specifična ponašanja u distribuiranim sistemima.
Perl-ov Shell modul i implicitno pozivanje komandi
Još jedan zanimljiv aspekt vezan za Izvršavanje vanjskih naredbi u Perlu je modul ShellOvaj modul vam omogućava pozivanje sistemskih programa kao da su Perl funkcije, zahvaljujući upotrebi AUTOLOAD.
Zamislite da učitavamo modul ovako:
use Shell qw(echo cat ps cp);
Od tog trenutka nadalje , kada napišete nešto poput:
$foo = echo("howdy", "funny", "world");
Ono što se dešava ispod je to Perl ne može pronaći potprogram pod nazivom echo i pucaj AUTOLOAD modulaOvaj mehanizam:
- Identifikujte naziv komande počevši od punog imena potprograma (
Shell::echo). - Dinamički konstruišite realnu funkciju koji će izvršiti tu sistemsku naredbu.
- Proslijedi poziv na novu funkciju, prenoseći primljene argumente.
Ako pregledate izvršenje pomoću Perl debuggera, vidjet ćete kako Argumenti su organizovani u @_ i konstruira se naredba koja treba pokrenuti.Rezultat trčanja echo Sakuplja se i skladišti u $foo, tako da:
print $foo;
Pokazat će nešto od stila howdy funny world s formatom koji generira echo sistemaOvaj pristup je praktičan, ali ga ne treba pretjerano koristiti jer može otežati čitljivost koda i rukovanje greškama.
Komanda exec u shell-u kao napredni alat za preusmjeravanje
Kao što smo vidjeli, naredba exec U ljusci se ne koristi samo da zamijeni ljusku.Umjesto toga, često se koristi za otvaranje, zatvaranje ili dupliranje deskriptora datoteka. Ova mogućnost omogućava kreiranje vrlo moćnih obrazaca u skriptama.
Na primjer, možda biste željeli trajno preusmjeri izlaz cijelog skripta u log datoteku bez potrebe da uradiš >>log.txt u svakom redu. Nešto poput:
exec >/var/log/mi_script.log 2>&1
Na ovaj način, i standardni izlaz i izlaz greške će ići u istu datoteku od početka skripte. Od tada, svaka komanda koja ne uspije ostavit će trag u dnevniku bez zatrpavanja terminala.
U drugim slučajevima, možda će vas zanimati povezati specifične deskriptore s privremenim datotekama da sačuvate podatke koje ćete kasnije obraditi. Zatvaranjem tih deskriptora sa exec n>&-Oslobađate resurse i sprječavate curenje rukovatelja.
Istina je da se ova vrsta konstrukcije ne viđa u osnovnim skriptama, ali kada počnete pisati ozbiljne administrativne alate, oni postaju gotovo neophodni za pravilnu kontrolu onoga što se vidi na ekranu, šta se sprema i kako su informacije strukturirane.
U konačnici, savladavanje exec-a kao naprednog alata za preusmjeravanje daje vam nivo kontrole nad shell skriptnim I/O operacijama koji čini razliku između "domaćih" skripti i robusnih produkcijskih alata.
Na kraju cijelog ovog putovanja, ključna ideja je da Funkcija exec, bilo da se radi o C-u, shell-u ili Perl-u, uvijek se vrti oko dvije ose: zamjene programa koji se izvršava i preciznog upravljanja ulazima i izlazima.Razumijevanje kako se oni kombinuju sa fork(), system, read ili moduli poput Shell Omogućava vam da dizajnirate čišća, efikasnija i sigurnija rješenja, bilo da se radi o pokretanju udaljenih procesa, enkapsulaciji složenih okruženja za izvršavanje ili jednostavnom pisanju skripti koje rade tačno ono što želite, bez iznenađenja.
Strastveni pisac o svijetu bajtova i tehnologije općenito. Volim dijeliti svoje znanje kroz pisanje, a to je ono što ću raditi na ovom blogu, pokazivati vam sve najzanimljivije stvari o gadžetima, softveru, hardveru, tehnološkim trendovima i još mnogo toga. Moj cilj je pomoći vam da se krećete u digitalnom svijetu na jednostavan i zabavan način.
