nohup i killall — proces koji preživi odjavu, i gašenje po imenu

Dve komande koje rešavaju dva česta problema. Prva: pokrenuo si nešto dugotrajno preko SSH-a, veza je pukla i posao je propao. Druga: proces se zaglavio, a ti nemaš volje da tražiš njegov PID.

Zašto proces uopšte umire pri odjavi

Kad se terminal zatvori, kernel svim procesima koji su za njega vezani šalje signal SIGHUP. Skraćeno od hangup — reč je ostala iz vremena modema, kad je „prekid veze" značio da je telefonska linija spuštena.

Podrazumevano ponašanje na taj signal je gašenje. Otud i klasičan scenario:

$ ssh server
$ ./migracija.sh          # traje dva sata
[veza puca posle 40 minuta]

$ ssh server
$ ps aux | grep migracija
$                         # nema ničega

Skripta je ubijena na četrdesetom minutu. Rešenje je da proces ili ne čuje taj signal, ili da uopšte ne bude vezan za terminal.

nohup

$ nohup ./migracija.sh &
[1] 4821
nohup: ignoring input and appending output to 'nohup.out'

Tri stvari se ovde desile:

  • nohup je procesu rekao da ignoriše SIGHUP
  • & ga je poslao u pozadinu, pa ti je prompt slobodan
  • izlaz je preusmeren u fajl nohup.out, jer terminal može nestati

Sada možeš zatvoriti vezu i posao će se nastaviti. Napredak pratiš kasnije:

$ tail -f nohup.out

Skoro uvek ćeš hteti sopstveni fajl

nohup.out nastaje u tekućem direktorijumu, a ako u njemu nemaš pravo pisanja, seli se u tvoj kućni direktorijum. Kad pokreneš tri posla, sva tri pišu u isti fajl i ispis se izmeša. Bolje odmah:

$ nohup ./migracija.sh > migracija.log 2>&1 &
[1] 4821

Sada su i izlaz i greške u fajlu koji si ti imenovao. Zapis 2>&1 i zašto redosled u njemu nije svejedno objašnjeno je u lekciji Piping i redirekcija.

Zapiši PID

$ nohup ./migracija.sh > migracija.log 2>&1 &
$ echo $! > migracija.pid
$ cat migracija.pid
4821

$! je PID poslednjeg posla poslatog u pozadinu. Bez toga ćeš proces kasnije tražiti kroz ps, a sa tim ga gasiš jednom komandom:

$ kill $(cat migracija.pid)

Zamka: skripta koja traži unos

nohup: ignoring input

Ova poruka nije upozorenje bez veze. nohup odvezuje standardni ulaz, pa svaka komanda koja negde usput pita „da li ste sigurni? [d/n]" odmah dobija kraj ulaza i prekida se. Zato pre pokretanja proveri da li program ima zastavicu za automatsko potvrđivanje:

$ nohup apt-get -y upgrade > upgrade.log 2>&1 &

Nisi pokrenuo sa nohup, a već je kasno

Klasična situacija: skripta radi već sat vremena i tek sad shvataš da si zaboravio. Ne moraš je prekidati.

^Z
[1]+  Stopped                 ./migracija.sh

$ bg
[1]+ ./migracija.sh &

$ disown -h %1

Redom: Ctrl+Z pauzira proces, bg ga nastavlja u pozadini, a disown -h ga skida sa spiska poslova koji dobijaju SIGHUP. Bez -h proces se potpuno uklanja sa spiska i više ga ne vidiš kroz jobs.

Jedno ograničenje: izlaz i dalje ide na taj terminal, pa kad se veza prekine, ispis nestaje. Proces preživljava, ali od tada radi naslepo.

Srodni alati

nohup kom & Unapred zaštićen, izlaz u fajl. Standardan izbor.
disown -h %1 Naknadna zaštita već pokrenutog procesa.
setsid kom Nova sesija, potpuno odvojena od terminala. Najčistije za servise.
screen, tmux Cela sesija preživi prekid, i možeš joj se vratiti.

Poslednji red je zapravo bolje rešenje za većinu situacija. Sa nohup proces radi, ali mu se ne možeš vratiti — vidiš samo log. Sa tmux-om se vratiš u istu sesiju i nastaviš gde si stao. Ako radiš preko SSH-a redovno, vredi ih naučiti; osnove udaljenog pristupa su preduslov.

killall

kill traži PID. killall traži ime:

$ killall firefox

Gasi sve procese tog imena odjednom. To je i prednost i opasnost — Firefox pokreće desetine procesa, i svi nestaju u jednoj komandi.

Prvo pogledaj šta ćeš pogoditi

Navika koja spasava:

$ pgrep -a nginx
891 nginx: master process /usr/sbin/nginx
892 nginx: worker process
893 nginx: worker process

pgrep pokazuje šta bi killall pogodio, ali bez posledica. Isti odnos kao echo pre rm.

Ako ti se ne piše dodatna komanda, tu je interaktivni režim:

$ killall -i firefox
Kill firefox(4821) ? (y/N) y
Kill firefox(4822) ? (y/N) n

Ime mora biti tačno

$ killall firefo
firefo: no process found

Za razliku od pkill, koji traži deo imena, killall traži poklapanje celog imena procesa. To je namerno i sigurnije je — pkill ngin bi pogodio i nešto sasvim drugo.

Ako ti ipak treba obrazac:

$ killall -r "^python[0-9]*$"

Kada TERM nije dovoljan

Podrazumevani signal je SIGTERM — pristojan zahtev programu da se ugasi. Program ga može ignorisati.

15 TERM Ugasi se uredno. Program stigne da sačuva i zatvori fajlove. Podrazumevano.
9 KILL Kernel ubija proces odmah. Ne može se ignorisati, ali nema čišćenja. Poslednja mera.
1 HUP Kod servisa obično znači „ponovo učitaj konfiguraciju", ne „ugasi se".
2 INT Isto što i Ctrl+C.
$ killall zaglavljen
$ sleep 5
$ pgrep zaglavljen
4821

$ killall -9 zaglavljen

Redosled je bitan: prvo TERM, sačekaj, pa tek onda KILL. Sa -9 program ne stiže ništa da sačuva — baza ostaje sa nedovršenom transakcijom, editor sa zaključanim fajlom.

Umesto ručnog čekanja postoji zastavica:

$ killall -w -s TERM aplikacija

-w čeka da procesi zaista nestanu pre nego što vrati prompt — korisno u skriptama, gde se odmah zatim pokreće nova verzija.

Ponovno učitavanje konfiguracije

$ sudo nginx -t
nginx: configuration file /etc/nginx/nginx.conf test is successful

$ sudo killall -HUP nginx

Sajt ne trpi prekid — nginx samo pročita novu konfiguraciju. Provera pre slanja signala nije opciona, jer sa greškom u konfiguraciji servis neće proći.

Korisne zastavice

$ killall -u marko                # svi procesi jednog korisnika
$ killall -o 2h python3           # stariji od dva sata
$ killall -y 10m node             # mlađi od deset minuta
$ killall -v httpd                # ispiši šta je ubijeno

Kombinacija -u i -o je klasika pri čišćenju zaglavljenih korisničkih sesija:

$ sudo killall -u marko -o 1d

Tri stvarne opasnosti

1. killall kao root

$ sudo killall sshd

Ubija i tvoju vezu. Isto važi za systemd, NetworkManager i sve što drži sistem u životu. Ako nisi siguran šta neki proces radi, prvo:

$ pgrep -a ime

2. Na nekim sistemima killall znači nešto sasvim drugo

Na Solarisu i pojedinim AIX sistemima killall ubija sve procese i gasi mašinu. Na Linuxu to nije slučaj, ali ako ikada budeš radio na tim sistemima, ova razlika se plaća skupo. Prenosiv izbor je pkill, koji svuda radi isto.

3. Ime duže od petnaest znakova

$ killall moja-duga-skripta.sh
moja-duga-skripta.sh: no process found

Kernel u pojedinim slučajevima čuva samo prvih petnaest znakova imena. Rešenje je -e za tačno poklapanje punog imena, ili pkill -f, koji traži kroz celu komandnu liniju:

$ pkill -f moja-duga-skripta.sh

Isto važi za skripte pokrenute kroz interpreter — killall migracija.sh neće naći ništa, jer se proces zapravo zove bash.

Kratka referenca

nohup

  • nohup kom & — pokreni tako da preživi odjavu
  • nohup kom > log 2>&1 & — sa sopstvenim logom
  • echo $! > kom.pid — zapamti PID
  • Ctrl+Z, bg, disown -h %1 — naknadna zaštita
  • setsid kom — potpuno odvajanje od terminala

killall

  • killall ime — TERM svim procesima tog imena
  • killall -9 ime — prisilno, poslednja mera
  • killall -HUP ime — ponovo učitaj konfiguraciju
  • killall -i ime — pitaj za svaki
  • killall -w ime — sačekaj da zaista nestanu
  • killall -u korisnik — svi procesi korisnika
  • killall -o 2h ime — samo stariji od dva sata
  • killall -r "obrazac" — po regularnom izrazu
  • pgrep -a ime — provera pre gašenja

Vežba

  1. Pokreni sleep 600 tako da preživi zatvaranje terminala, sa izlazom u fajl ~/proba.log. Zatvori terminal, otvori novi i proveri da li proces još radi.
  2. Pokreni sleep 600 normalno, pa ga naknadno zaštiti bez prekidanja.
  3. Pokreni tri instance komande sleep 900, pa ih sve ugasi jednom komandom — ali prvo proveri šta bi ta komanda pogodila.
  4. Napravi skriptu koja u petlji ispisuje vreme svakih pet sekundi, pokreni je preko nohup, prati je sa tail, pa je ugasi koristeći zapisan PID.
  5. Objasni sebi zašto killall sa imenom te skripte ne bi radio, i pronađi komandu koja bi.

Peti zadatak je najvažniji na celoj stranici.


Gašenje po PID-u je na stranici kill, po delu imena na stranicama pgrep i pkill, a rad sa poslovima u pozadini na stranicama jobs, bg i fg.

Cela lekcija je deo vodiča Linux osnove.

Comments

Popular posts from this blog

Početak u Linuxu — šta je i zašto se uči

Konverzija tipova podataka u Pythonu

groupadd