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:
nohupje procesu rekao da ignorišeSIGHUP&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 odjavunohup kom > log 2>&1 &— sa sopstvenim logomecho $! > kom.pid— zapamti PIDCtrl+Z,bg,disown -h %1— naknadna zaštitasetsid kom— potpuno odvajanje od terminala
killall
killall ime— TERM svim procesima tog imenakillall -9 ime— prisilno, poslednja merakillall -HUP ime— ponovo učitaj konfiguracijukillall -i ime— pitaj za svakikillall -w ime— sačekaj da zaista nestanukillall -u korisnik— svi procesi korisnikakillall -o 2h ime— samo stariji od dva satakillall -r "obrazac"— po regularnom izrazupgrep -a ime— provera pre gašenja
Vežba
- Pokreni
sleep 600tako da preživi zatvaranje terminala, sa izlazom u fajl~/proba.log. Zatvori terminal, otvori novi i proveri da li proces još radi. - Pokreni
sleep 600normalno, pa ga naknadno zaštiti bez prekidanja. - Pokreni tri instance komande
sleep 900, pa ih sve ugasi jednom komandom — ali prvo proveri šta bi ta komanda pogodila. - 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. - Objasni sebi zašto
killallsa 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
Post a Comment