Chcete zlepšit tuto otázku? Přidejte podrobnosti a objasněte problém úpravou tohoto příspěvku.
Zavřeno před 3 lety.
Vylepšete tuto otázku
Pro pochopení
Pokud Bash čeká na dokončení příkazu a přijme signál
o tom, že byla past nastavena, past nebude provedena, dokud nebude dokončen příkaz
.Když Bash čeká na asynchronní příkaz prostřednictvím vestavěné funkce čekání ,
příjem signálu, pro který byla nastavena past, způsobí, že se
vestavěné čekání okamžitě vrátí s výstupním stavem vyšším než
128, ihned po kterém se past provede.
z manuálu Bash,
spouštím následující:
-
V mých dvou příkladech SIGINT (odesláno pomocí Ctrl-C) ukončí
úlohu v popředí (první případ v uvozovkách) a úlohu na pozadí
(druhý případ v uvozovkách), obě okamžitě, bez čekání aby je
dokončili.Znamená první věta v uvozovkách, že pokud Bash spouští
úlohu v popředí a přijímá signálSIGINT
, past signáluSIGINT
, když je nastaven, bude prováděn, dokud se příkaz nedokončí?
Pokud ano, proč v mém prvním příklaductrl-C
zajistit, aby úloha
v popředí existovala bezprostředně před dokončením?$ sleep 10000 # a foreground job ^C $ sleep 10000 & # a background job [1] 21219 $ wait 21219 ^C $ echo $? 130
-
Co znamená „signál, na který byla nastražena past“ znamená,
-
signál
arg
jehož past byla specifikována pomocítrap arg sigspec
nebo -
signál, který není ignorován, nebo
-
signál, jehož past není výchozí?
V příkladech v mé části 1 jsem nenastavil past pro SIGINT, takže signál má svůj
výchozí handler (který se vymaní z jakékoli spouštěcí smyčky). Je
signál s výchozí obslužnou rutinou považováno za past, která byla
nastražena? -
-
Nastavil jsem past pro
SIGINT
, alectrl-C
před dokončením ukončí následující
příkaz. Je to tedy v rozporu s první
větou v mé citaci?$ trap "echo You hit control-C!" INT $ bash -c 'sleep 10; echo "$?"' ^C $
Před nastavením pasti pro
SIGINT
,ctrl-C
také provede
ukončení stejného příkazu před dokončením. Je to tedy v rozporu s první
větou v mé citaci?$ bash -c 'sleep 10; echo "$?"' ^C
-
Mohl byste uvést nějaké příklady, které by vysvětlily, co znamenají dvě věty v
citátu?
Děkuji.
Přijatá odpověď:
Co znamená „signál, na který byla nastražena past“?
To je signál, pro který byl definován handler (s trap 'handling code' SIG
), kde manipulační kód není prázdný, protože by to způsobilo ignorování signálu.
Takže signály, které mají svou výchozí polohu, nejsou signály, pro které byla nastražena past.
Některé z citátů ve vašem příspěvku se vztahují i na signály, které mají výchozí polohu, i když zjevně nejde o část o spuštění past , protože pro ně nebyla definována žádná past.
Manuál hovoří o doručování signálu do shellu , nikoli na příkazy, které spouštíte z tohoto shellu.
1.
Pokud Bash čeká na dokončení příkazu a přijme signál, pro který byla past nastavena, past nebude provedena, dokud nebude příkaz dokončen.
(1)
proč v mém prvním příkladu způsobí ctrl-C ukončení úlohy v popředí bezprostředně před jejím dokončením
Pokud spustíte sleep 10
na výzvu interaktivního shellu , shell umístí tuto úlohu do popředí (prostřednictvím ioctl()
na zařízení tty, které sděluje disciplíně terminálové linky, která skupina procesů je ta v popředí), takže pouze sleep
dostane SIGINT po ^C
a interaktivní shell nebude , takže není užitečné toto chování testovat.
-
Nadřazený shell, protože je interaktivní, neobdrží SIGINT, protože jeho proces není ve skupině procesů v popředí.
-
Každý příkaz může volně nakládat se signály, jak chce.
sleep
nedělá nic speciálně se SIGINTem, takže získá výchozí dispozici (ukončí se), pokud nebyl SIGINT při spuštění ignorován.
(2) Pokud spustíte sleep 10
v neinteraktivním shellu ,
bash -c 'sleep 10; echo "$?"'
Oba neinteraktivní bash
shell a sleep
obdrží SIGINT, když stisknete Ctrl-C.
Pokud bash
okamžitě ukončeno, mohlo by to opustit sleep
příkaz běží bezobslužně na pozadí, pokud náhodou ignoruje nebo zpracovává signál SIGINT. Takže místo toho
bash
jako většina ostatních shellů, bloky příjem signálů (alespoň některých signálů) při čekání na příkazy.- Doručování je obnoveno po ukončení příkazu (přičemž se provedou depeše). To také zabrání tomu, aby se příkazy v pastech spouštěly souběžně s jinými příkazy.
Ve výše uvedeném příkladu sleep
zemře na SIGINT, takže bash
nemusí dlouho čekat, než zvládne svůj vlastní SIGINT (tady zemře, protože jsem nepřidal trap
na SIGINT).
(3) když stisknete Ctrl+C při spuštění neinteraktivního shellu:
bash -c 'sh -c "trap "" INT; sleep 3"; echo "$?"'
(bez trap
na SIGINT) bash
není zabit SIGINTEM. bash
, stejně jako několik dalších shellů zachází se SIGINT a SIGQUIT speciálně. Implementují čekací a kooperativní ukončení chování popsané na https://www.cons.org/cracauer/sigint.html (a je známo, že způsobuje několik nepříjemností, jako jsou skripty volající příkazy zpracování SIGINT, které nelze přerušit pomocí ^C
)
(4) Pro správné testování byste měli spustit neinteraktivní bash
který má nastavenou past SIGINT a zavolá příkaz, který nezemře ihned po SIGINT jako:
bash -c 'trap "echo Ouch" INT; sh -c "trap "" INT; sleep 3"'
bash
čeká na sh
který má (spolu s sleep
) SIGINT ignorován (kvůli trap "" INT
), takže SIGINT nezabije sleep
ani sh
. bash
neignoruje SIGINT, ale jeho zpracování je odloženo do sh
se vrací. Vidíte Ouch
zobrazen, nikoli po Ctrl+C , ale po sleep
a sh
byly normálně ukončeny.
Všimněte si, že trap
příkaz nastaví past na signál pro stejný shell, ve kterém běží. Takže když trap
příkaz se provádí mimo neinteraktivní shell a v nadřazeném shellu,
$ trap "echo You hit control-C!" INT $ bash -c 'sleep 10; echo "$?"' ^C $
neinteraktivní bash
a sleep
příkazy tuto trap
nezdědí z nadřazeného shellu. Po provedení jiného příkazu (execve()
se obslužné programy signálů ztratí vymaže celý adresní prostor procesu včetně kódu handleru). Na execve()
, signály, které měly definovaný handler, se vrátí do výchozího uspořádání, ty, které byly ignorovány, zůstanou ignorovány.
Kromě toho ve většině shellů trap
s jsou také resetovány v dílčích shellech.
2.
Když Bash čeká na asynchronní příkaz prostřednictvím vestavěné funkce čekání , příjem signálu, pro který byla nastavena past, způsobí, že se zabudované čekání okamžitě vrátí se stavem ukončení větším než 128, ihned po kterém se past provede.
Při použití wait
explicitně , wait
je přerušen jakýmkoliv signálem, který má nastraženou past (a samozřejmě také těmi, které zabíjejí shell úplně).
To ztěžuje spolehlivé získání výstupního stavu příkazu, když jsou zachyceny signály :
$ bash -c 'trap "echo Ouch" INT; sh -c "trap "" INT; sleep 10" & wait "$!"; echo "$?"'
^COuch
130
V takovém případě sleep
a sh
nebyli zabiti SIGINTEM (protože to ignorují). Stále wait
vrátí s 130
návratový stav, protože během čekání na sh
byl přijat signál (SIGINT). . Budete muset zopakovat wait "$!"
do sh
skutečně ukončí, aby získal sh
stav ukončení.