GNU/Linux >> Znalost Linux >  >> Linux

Proč při psaní Ctrl-c v terminálu není úloha v popředí ukončena, dokud není dokončena?

Zavřeno . Tato otázka vyžaduje podrobnosti nebo jasnost. Momentálně nepřijímá odpovědi.

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í:

  1. 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ál SIGINT , past signálu
    SIGINT , když je nastaven, bude prováděn, dokud se příkaz nedokončí?
    Pokud ano, proč v mém prvním příkladu ctrl-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
    
  2. 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?

  3. Nastavil jsem past pro SIGINT , ale ctrl-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
    
  4. 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.

Související:Linux – Zvýšit hlasitost MKV videa z Linuxového terminálu?

(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ě).

Související:Jak rychle naformátovat oddíl na souborový systém?

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í.


Linux
  1. Proč je Bash Prompt odposloucháván, když procházím historii?

  2. Proč (a jak) používání Cat na binárních souborech zkazilo terminál?

  3. Proč má více instancí Mate-terminálu stejné PID?

  1. Proč The Iptables Persistent Service neukládá změny?

  2. Proč Wget nezemřel po ztrátě připojení Ssh?

  3. zavolejte funkci po dokončení programu pomocí ctrl c

  1. Kdy je setsid() užitečné nebo proč potřebujeme seskupovat procesy v Linuxu?

  2. proč se smyčka bash while neukončí při napojení na ukončený dílčí příkaz?

  3. Proč clang při přesměrování generuje nesrozumitelný text?