Dla administratora w jego codziennej działalności najporęczniejszą komendą do obserwacji
procesów w systemie jest top|htop
. Do uzyskania obrazu całego drzewa genealogicznego
procesów wygodnie jest użyć komendy pstree -[ch]
.
Podstawową komendą do szczegółowej analizy działania procesów w systemie jest ps
(zob. man ps
). Korzystając z tej komendy można używać opcji podawanych w stylu UNIX,
BSD oraz GNU.
Obserwacja procesów związanych z daną sesją:
# ps
# ps -w
# ps -f|F
# ps -f -t tty1
# ps -fw
# ps -l
# ps -lf
# ps -L[f]
# ps -Fl
Obserwacja procesów w systemie:
# ps -e
# ps -ew
# ps -e[fF]
# ps -ef -t pts/14
# ps -ef -t tty1
# ps -ejH
# ps -U user
Przykłady opcji w stylu BSD wg stron podręcznika:
# ps ax
# ps axu
# ps axjf
# ps axms
# ps axZ
Można użyć komendy ps
do uzyskania wskazanych parametrów procesów, łącznie z własnym
opisem i określeniem wielkosci pola, na którym będą zapisywane:
# ps -eo pid:10,tid,class,rtprio,ni,pri,psr:5,pcpu:5,stat:5,wchan:24,comm
# ps -eo uid=user_id,pid=process_id,comm=command_name
Jeśli są uruchomione/wstrzymane jakieś procesy, to można nimi zarządzać poprzez komendy
jobs
, fg
, bg
.
Jaki sens mają parametry guid i sid? Jakim procesom odpowiadają te wartości?
Można się o tym przekonać wykonując poniższe komendy i analizując dokładnie wyniki
działania komendy ps
:
# ls /usr/bin | more &
# vi xxx &
# ps -elf| grep a | more &
# ps -o uid,pid,pgid,sid,stat,cmd
Zob. także Procesy, procesy lekkie, wątki jądra i ich stany.
Co oznacza parametr PRI? prio=priotytet wg jądra (zob. /proc/PID/sched).
proces/wątek |
prio |
top/htop |
ps -eo pri |
ps -eo rtprio |
ps -el |
nice |
migration |
0 |
RT |
139 |
99 |
-40 |
|
kworker |
100 |
0 |
39 |
60 |
-20 |
|
bash |
120 |
20 |
19 |
80 |
0 |
|
khugepaged |
139 |
39 |
0 |
99 |
19 |
komenda |
prio <100 |
prio >= 100 |
top/htop |
PRI= RT |
PRI= prio - 100 |
ps -eo pri |
PRI= 139 - prio |
PRI= 139 - prio |
ps -el |
PRI= prio - 40 |
PRI= prio - 40 |
Wraz z wprowadzeniem jądra 2.6.23 (10/2007) planista O(1) został zastąpiony planistą całkowicie sprawiedliwym (CFS, Completely Fair Scheduler), który przydziela kwanty czasu zmiennej długości temu zadaniu (procesowi), które go najbardziej potrzebuje; zob. https://en.wikipedia.org/wiki/Completely_Fair_Scheduler.
Zadania przydzielane są do klas, w których obowiązuje wspólna polityka przydziału CPU. W klasie fair możemy mieć zadania typu:
SCHED_NORMAL (zw. także SCHED_OTHER) – polityka przydziału dla zwykłych zadań
SCHED_BATCH – rzadsze wywłaszczanie, zadania wykonują się dłużej, lepsze wykorzystanie pamięci podręcznej procesorów; polityka właściwa dla zadań wsadowych
W klasie idle:
SCHED_IDLE – polityka przydziału słabsza, niż dla zadań ‘nice 19’; zadanie jest wykonywane, kiedy praktycznie procesor nie ma innych zadań do wykonania
W klasie real time:
SCHED_FIFO
SCHED_RR.
Od wersji 3.14 jest także dostępna klasa DEADLINE (zob. https://en.wikipedia.org/wiki/SCHED_DEADLINE).
Do nadawania i zmiany prorytetów służy komenda chrt
, a do zmiany pozmiomów uprzejmości
– nice|snice
.
Przykłady zmiany priorytetów procesów:
# chrt -b -p 0 PID
# chrt -r -p 99 PID
# chrt -r -p 98 PID
# chrt -p PID
# chrt -b -p 0 PID
# renice +19 PID
# renice -20 PID
# nice -n +19 top -d .5
Sygnały to jeden z mechanizmów komunikacji międzyprocesowej używany w systemach linuksowych (ogólnie uniksopodobnych). Sygnały są krótkimi wiadomościami, które można wysyłać do procesu lub grupy procesów. Z każdym sygnałem jest związana jego nazwa i numer (zależne od platformy). Jest to mechanizm zarządzania procesami dostępny w trybie użytkownika. Sygnały informują proces o wystąpieniu określonego zdarzenia i powodują, że proces wykonuje zawartej w kodzie procesu funkcję obsługi danego sygnału.
Pełną listę sygnałów można znaleźć na stronach podrecznika systemowego (man 7 signal
)
lub wykonując komendę kill -l
.
Do zarządzania procesami poprzez sygnały używa się następujących komend: pgrep
,
pkill
, skill
, killall
.
W celu wyprobowania działania tych komend należy utworzyć zestaw procesów wykorzystując do
tego takie skrypty jak create2kill1.sh
(w trybie
tekstowym) oraz
create2kill2.sh
(w trybie graficznym).
Po uruchomieniu skryptu (np. create2kill1.sh start
) można łatwo sprawdzić, jakie
procesy zostały utworzone (create2kill1.sh status
) i które są wybierane przy
zastosowaniu komend:
# pgrep [-l] proc
# pgrep [-l] procA|B
# pgrep [-l] 111|222
# pgrep [-l] [-f] num
# pgrep [-l] [-f] num=
# pgrep [-l] [-f] 12:26
Uwaga! Jeśli w przykładach pojawia się ciąg znaków postaci hh:mm, to trzeba go zastąpić właściwym czasem utworzenia procesów.)
Stosując odpowiednie wyrażenie regularne można spowodować usunięcie wybranego procesu.
Kilka dalszych przykładów:
# pgrep -f './111procA'
# pgrep [-l] '[12]proc'
# pgrep [-l] '[:digit:]{3}proc'
# pgrep [-l] '[ [:digit:] ]{3}proc'
# pgrep [-l] '[ [:digit:] ]{2}proc'
# pgrep [-l] '^[ [:digit:] ]{2}proc'
# pgrep [-l] '^[ [:digit:] ]{3}proc'
# pgrep -l '2.rocA'
# pgrep -l '2p.rocA'
# pgrep -l '2p.ocA'
# pgrep -l '2.....B'
# pgrep '\./111procA'
# pgrep -f '\./111procA'
# pgrep -f '\.\/111procA'
# pgrep -f '.\/111procA'
# pgrep -f '../111procA'
# pgrep -f './111procA'
# pkill -f './111procA'
# pgrep '11:42'
# pgrep -f '11:42'
# pgrep -t pts/0
Zob. także Killing processes that don’t want to die https://lwn.net/Articles/754980/.
System operacyjny pozwala na kontrolę zasobów zużywanych przez poszczególne
procesy. Powłoka bash udostępnia komendę ulimit
, dzięki której można kontrolować
dostęp procesów do zasobów (man bash
). Rozróżnia się ograniczenia miękkie i twarde.
Użytkownik może modyfikować ograniczenia twarde tylko ``w dół’’, a ograniczenia miękkie
``w dół’’ i ``w górę’’, ale tylko do wielkości wyznaczonej przez ograniczenia sztywne.
Jeśli twarde ograniczenie nie jest ustalone w /etc/security/limits.conf, a ulimit -H -t
pokazuje unlimited, to nie można go zmienić z poziomu użytkownika, gdyż trzeba
jednocześnie zmienić twarde i miękkie ograniczenie. Jeśli jednak użytkownik określi
miękkie ograniczenie, np. ulimit -S -t 1000
, to zadziała także komenda ulimit -H -t
1000
. Prawidłowa kolejność jest następująca:
# ulimit -a
# ulimit -aH
# ulimit -aS
# ulimit -t 1000
# ulimit -aH|S
# ulimit -St 1100
# ulimit -St 200
# ulimit -St 500
# ulimit -Ht 400
# ulimit -St 200
# ulimit -Ht 300
Ograniczenia H i S muszą być tak modyfikowane, aby nigdy ograniczenie twarde nie przyjmowało wartości mniejszej od ograniczenia miękkiego.
Zob.
W celu zaobserwowania przekierowań należy porównać i przeanalizować działania poniższych komend:
# ls -l /etc/hosts /etc/passwdd
ls: cannot access /etc/passwdd: No such file or directory
-rw-r--r-- 1 root root 4068 maj 20 17:43 /etc/hosts
# ls -l /etc/hosts /etc/passwdd > ls.lst
ls: cannot access /etc/passwdd: No such file or directory
# ls -l /etc/hosts /etc/passwdd 1> ls.lst
ls: cannot access /etc/passwdd: No such file or directory
# ls -l /etc/hosts /etc/passwdd 2> ls.lst
-rw-r--r-- 1 root root 4068 maj 20 17:43 /etc/hosts
# ls -l /etc/hosts /etc/passwdd >& ls.lst
Jak się ma zawartość pliku ls.lst do komunikatów wyświetlanych na konsoli?
Uwaga! Przy wykonywaniu poniższych komend trzeba pamiętać, żeby przed wykonaniem kolejnej usuwać pliki ls.lst i ls.err.
# ls -l /etc/hosts /etc/passwdd 1> ls.lst 2>ls.err
# cat ls.err
# ls -l /etc/hosts /etc/passwdd 1> ls.lst 2>&1
# cat ls.lst
ls: cannot access /etc/passwdd: No such file or directory
-rw-r--r-- 1 root root 1910 Dec 10 19:26 /etc/hosts
# ls -l /etc/hosts /etc/passwdd 2>&1 1> ls.lst
ls: cannot access /etc/passwdd: No such file or directory
Co zawierają pliki ls.lst i ls.err? Dlaczego w ostatnim przykładzie błędy są kierowane na terminal?
Wielokrotna zmiana przekierowania:
# ls -l /etc/hosts /etc/passwdd 1>ls1.lst 1>ls2.lst
Jakiej długości są oba pliki? W jakiej kolejności wyprowadzane są komunikaty?
Poniższe komendy są równoważne
# ls -l /etc/hosts /etc/passwdd 1>ls.lst 2>&1
# ls -l /etc/hosts /etc/passwdd 2>&1 1>ls.lst 2>&1
# cat ls.lst
ls: cannot access /etc/passwdd: No such file or directory
-rw-r--r-- 1 root root 2073 kwi 4 10:40 /etc/hosts
Poniższe także, ale dają inny wynik
# ls -l /etc/hosts /etc/passwdd 2>&1 2>ls.lst 1>ls.lst
# ls -l /etc/hosts /etc/passwdd 2>ls.lst 1>ls.lst
# cat ls.lst
-rw-r--r-- 1 root root 2073 kwi 4 10:40 /etc/hosts
rectory
Z porównania wynika, że najpierw wyprowadzana jest zawartość bufora związanego z deskryptorem 2, a dopiero później – z deskryptorem 1.
Korzystanie z niestandardowych deskryptorów plików:
Jak utworzyć plik o zerowej długości lub wyzerować już istniejący plik?
# : > hosts
Jak powiązać deskryptor pliku z plikiem?
# cp /etc/hosts hosts
# exec 10<hosts
Ile razy można wykonać komendę cat <&10
?
Dane z deskryptora 10 można czytać wiersz po wierszu:
# exec 10<hosts
# read line <&10
# echo $line
# read line <&10
# echo $line
W każdej chwili można deskryptor zamknąć:
exec 10>&-
read line <&10
Porównać komendę cat /etc/hosts |less
z komendami
# 0</etc/hosts less
# </etc/hosts less
Znaczenie symboli &-, <&-, 2>&-:
zamykanie deskryptora pliku n do odczytu: n<&-
zamykanie STDIN: 0<&-
, <&-
zamykanie deskryptora n pliku do zapisu: n>&-
zamykanie standardowego wyjścia: 1>&-
, >&-
W jednym terminalu mamy sesję basha o numerze np. 4717 (echo $$
). W drugim
terminalu można obserwować pliki związane z tym procesem przy użyciu komendy: lsof -a -p 4717 -d0,1,2,3,10
(komendę lsof
trzeba wywoływać jako użytkownik ‘root’!).
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
bash 4717 jkob 0u CHR 136,13 0t0 16 /dev/pts/13
bash 4717 jkob 1u CHR 136,13 0t0 16 /dev/pts/13
bash 4717 jkob 2u CHR 136,13 0t0 16 /dev/pts/13
Wygodniej jest te obserwacje robić dla komendy ping
wywoływanej z różnymi przekierowaniami:
# ping localhost
# lsof -a -p `pgrep ping` -d0,1,2
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
ping 12543 root 0u CHR 136,28 0t0 31 /dev/pts/28
ping 12543 root 1u CHR 136,28 0t0 31 /dev/pts/28
ping 12543 root 2u CHR 136,28 0t0 31 /dev/pts/28
# ping localhost > ping.out
# lsof -a -p `pgrep ping` -d0,1,2
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
ping 13259 root 0u CHR 136,28 0t0 31 /dev/pts/28
ping 13259 root 1w REG 8,17 810 139202 /root/ping.out
ping 13259 root 2u CHR 136,28 0t0 31 /dev/pts/28
# ping localhost 1> ping.out 2>ping.err
# lsof -a -p `pgrep ping` -d0,1,2
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
ping 13474 root 0u CHR 136,28 0t0 31 /dev/pts/28
ping 13474 root 1w REG 8,17 601 139202 /root/ping.out
ping 13474 root 2w REG 8,17 0 173991 /root/ping.err
# ping localhost 1> ping.out 2>&1
# lsof -a -p `pgrep ping` -d0,1,2
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
ping 13915 root 0u CHR 136,28 0t0 31 /dev/pts/28
ping 13915 root 1w REG 8,17 394 139202 /root/ping.out
ping 13915 root 2w REG 8,17 394 139202 /root/ping.out
# ping localhost 2>&1 1>ping.out
# lsof -a -p `pgrep ping` -d0,1,2
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
ping 14122 root 0u CHR 136,28 0t0 31 /dev/pts/28
ping 14122 root 1w REG 8,17 950 139202 /root/ping.out
ping 14122 root 2u CHR 136,28 0t0 31 /dev/pts/28
Do obserwacji przekierowań można także wykorzystać komendę xargs
.
Potok jest połączony ze standardowym wyjściem:
# ls -la /etc/passwdd /etc/hosts | xargs -I{} echo '###' {} '###'
Standardowe wyjście błędów jest kopią wyjścia standardowego:
# ls -la /etc/passwdd /etc/hosts 2>&1 | xargs -I{} echo '###' {} '###'
Któryś ze strumieni wyjściowych jest usuwany:
# ls -la /etc/passwdd /etc/hosts 1>/dev/null | xargs -I{} echo '###' {} '###'
# ls -la /etc/passwdd /etc/hosts 2>/dev/null | xargs -I{} echo '###' {} '###'
Manipulacji na deskryptorach można dokonywać w dowolnym miejscu komendy:
# 2>&1 ls -la /etc/passwdd /etc/hosts | xargs -I{} echo '###' {} '###'
# ls -la /etc/passwdd /etc/hosts 2>&1 | xargs -I{} echo '###' {} '###'
Potok jest połączony ze standardowym wyjściem i standardowym wyjściem dla błędów:
# ls -la /etc/passwdd /etc/hosts |& xargs -I{} echo '###' {} '###'
Żadna wiadomość nie jest przekazywana do procesu xargs:
# 1>&2 ls -la /etc/passwdd /etc/hosts | xargs -I{} echo '###' {} '###'
# ls -la /etc/passwdd /etc/hosts 1>&2 | xargs -I{} echo '###' {} '###'
W przypadku zastosowania |& sprzęganie strumieni zachodzi inaczej (dlaczego?):
# ls -la /etc/passwdd /etc/hosts 1>/dev/null |& xargs -I{} echo '###' {} '###'
# ls -la /etc/passwdd /etc/hosts 2>/dev/null |& xargs -I{} echo '###' {} '###'