Gerenciamento de processos no Bash
Curso de Bash
Seção do curso de Bash sobre como listar (ps, pgrep), terminar (kill, pkill),controlar (bg, fg, jobs) e cronometrar (time) processos.
Processo é a execução de um programa. Cada vez que um comando é executado, um novo processo é criado. O mesmo comando executado diversas vezes gerará processos distintos.
Processos podem ser iniciados por usuários (via interface gráfica ou terminal), pelo SO ou por um processo pai (processo que dá origem a outros processos chamados de filhos/descendentes).
Conteúdo
Listando processos com ps
ps
exibe uma lista dos processos ativos atrelados ao usuário atual e que estão sendo executados no terminal atual.
PID
é o identificador único do processo, TTY
é o terminal no qual o processo foi iniciado, TIME
é o tempo de processamento acumulado e CMD
o nome do comando relativo ao processo.
ps
PID TTY TIME CMD
3638 pts/0 00:00:00 bash
13565 pts/0 00:00:00 ps
Assim que ps
exibe sua saída seu processo é encerrado por isso duas execuções de ps
sempre terão PIDs diferentes como o PID da saída acima que difere do da saída abaixo.
ps
PID TTY TIME CMD
3638 pts/0 00:00:00 bash
13900 pts/0 00:00:00 ps
O tempo de processamento acumulado exibe apenas segundos inteiros, então comandos que tomam milisegundos para se encerrar não são exibidos até que o tempo acumulado ultrapasse um segundo.
O comando abaixo não tem saída, apenas consome tempo de processador.
for i in {1..1000000}; do :; done
Agora ps
exibe na coluna TIME
o tempo de processamento acumulado de bash
com um novo valor.
ps
PID TTY TIME CMD
3638 pts/0 00:00:01 bash
13965 pts/0 00:00:00 ps
A opção -f
de ps
exibe o formato completo. UID
é o nome do usuário dono do processo, PPID
é o PID do processo pai que iniciou o processo atual, C
utilização do processador expressa em percentual e STIME
hora ou dia em que o processo foi iniciado. CMD
passa a exibir as opções e argumentos do comando, além de eventualmente o caminho absoluto do comando.
ps -f
UID PID PPID C STIME TTY TIME CMD
caio 3638 3626 0 13:37 pts/0 00:00:01 /bin/bash
caio 14249 3638 0 16:24 pts/0 00:00:00 ps -f
-p
exibe apenas a linha relativa ao PID especificado como seu argumento.
ps -f -p 3638
UID PID PPID C STIME TTY TIME CMD
caio 3638 3626 0 13:37 pts/0 00:00:01 /bin/bash
A opção -e
exibe todos os processos, incluindo processos que não foram iniciados pelo usuário atual e processos que estão em execução em outros terminais ou mesmo sem terminal associado.
ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 13:36 ? 00:00:02 /sbin/init splash
root 2 0 0 13:36 ? 00:00:00 [kthreadd]
root 3 2 0 13:36 ? 00:00:00 [rcu_gp]
root 4 2 0 13:36 ? 00:00:00 [rcu_par_gp]
[... Dúzias de linhas omitidas]
Entendendo a saída de ps -ef
Cada novo processo tem atribuído a si um PID maior que o do processo anterior. Então, processos com PID menor estão em execução por mais tempo.
Os primeiros PIDs pertencem à processos iniciados durante a inicialização do SO: O primeiro (PID 1) sendo init
, responsável por iniciar todos os outros processos e o segundo sendo [kthreadd]
, um serviço não interativo que cria threads utilizadas pelo núcleo do SO. Todas as threads são filhas de [kthreadd]
e contêm []
envolta de seu nome.
Em SOs que utilizam systemd , systemd --user
é o primeiro processo atribuído ao usuário atual e tem por função gerenciar processos sob controle do usuário atual. Perceba que todos os seus processos descendentes estão atribuídos ao usuário atual.
Na saída parcial de ps -ef
abaixo firefox
é filho de gnome-shell
pois foi iniciado por meio de interface gráfica. gnome-shell
é o processo responsável pelo ambiente gráfico (GNOME) utilizado no meu SO.
UID PID PPID C STIME TTY TIME CMD
caio 1847 1 0 13:37 ? 00:00:01 /lib/systemd/systemd --user
caio 2545 1847 2 13:37 ? 00:03:45 /usr/bin/gnome-shell
caio 3001 2545 2 13:37 ? 00:03:49 /usr/lib/firefox/firefox
Neste outro trecho da saída, temos o firefox
como filho de bash
porque o navegador foi iniciado do terminal e bash
, por sua vez, é filho de tilix
, um aplicativo de terminal.
UID PID PPID C STIME TTY TIME CMD
caio 1847 1 0 13:37 ? 00:00:01 /lib/systemd/systemd --user
caio 3626 1847 0 13:37 ? 00:00:54 /usr/bin/tilix
caio 3638 3626 0 13:37 pts/0 00:00:01 /bin/bash
caio 20173 3638 17 17:20 pts/0 00:00:00 /usr/lib/firefox/firefox --new-instance -P
Filtrando processos com pgrep
pgrep
exibe os PIDs do processos cujos nomes correspondam a um padrão. Comando especialmente útil para buscar processos que tenham muitos descendentes.
pgrep
compara com o padrão apenas os nomes dos comandos. Abaixo, pgrep
recebe o padrão firefox
como argumento e exibe todos os processos cujo nome do comando corresponde à firefox
.
pgrep firefox
3305
-a
adiciona a linha completa do comando à saída.
pgrep -a firefox
3305 /usr/lib/firefox/firefox
-f
compara com o padrão, a linha completa do comando (o que inclui seus argumentos, opções e o caminho absoluto). Formato similar à coluna CMD
de ps -f
.
pgrep -a -f firefox
3305 /usr/lib/firefox/firefox
3444 /usr/lib/firefox/firefox -contentproc -childID 2 -isForBrowser -prefsLen 6593 -prefMapSize 244025 -parentBuildID 20201112153044 -appdir /usr/lib/firefox/browser 3305 true tab
3544 /usr/lib/firefox/firefox -contentproc -childID 4 -isForBrowser -prefsLen 7391 -prefMapSize 244025 -parentBuildID 20201112153044 -appdir /usr/lib/firefox/browser 3305 true tab
8292 /usr/lib/firefox/firefox -contentproc -childID 16 -isForBrowser -prefsLen 10754 -prefMapSize 244025 -parentBuildID 20201112153044 -appdir /usr/lib/firefox/browser 3305 true tab
10098 /usr/lib/firefox/firefox -contentproc -childID 17 -isForBrowser -prefsLen 10752 -prefMapSize 244025 -parentBuildID 20201112153044 -appdir /usr/lib/firefox/browser 3305 true tab
10137 /usr/lib/firefox/firefox -contentproc -childID 18 -isForBrowser -prefsLen 10752 -prefMapSize 244025 -parentBuildID 20201112153044 -appdir /usr/lib/firefox/browser 3305 true tab
Expressões Regulares Estendidas de grep
podem ser utilizadas como padrão. O padrão (f.+x/?){2}$
é correspondido por todas as linhas completas de comando que contenham uma sequência iniciando com f
e terminando com x
, opcionalmente seguido por /
seguido da mesma sequência.
pgrep -af "(f.+x/?){2}$"
3305 /usr/lib/firefox/firefox
-o
exibe apenas o processo mais antigo.
pgrep -af -o firefox
3305 /usr/lib/firefox/firefox
-P
exibe os processos cujo pai tem o PID especificado.
pgrep -a -P 38618
3444 /usr/lib/firefox/firefox -contentproc -childID 2 -isForBrowser -prefsLen 6593 -prefMapSize 244025 -parentBuildID 20201112153044 -appdir /usr/lib/firefox/browser 3305 true tab
3542 /usr/bin/python3 /usr/bin/chrome-gnome-shell /usr/lib/mozilla/native-messaging-hosts/org.gnome.chrome_gnome_shell.json chrome-gnome-shell@gnome.org
3544 /usr/lib/firefox/firefox -contentproc -childID 4 -isForBrowser -prefsLen 7391 -prefMapSize 244025 -parentBuildID 20201112153044 -appdir /usr/lib/firefox/browser 3305 true tab
8292 /usr/lib/firefox/firefox -contentproc -childID 16 -isForBrowser -prefsLen 10754 -prefMapSize 244025 -parentBuildID 20201112153044 -appdir /usr/lib/firefox/browser 3305 true tab
10098 /usr/lib/firefox/firefox -contentproc -childID 17 -isForBrowser -prefsLen 10752 -prefMapSize 244025 -parentBuildID 20201112153044 -appdir /usr/lib/firefox/browser 3305 true tab
10137 /usr/lib/firefox/firefox -contentproc -childID 18 -isForBrowser -prefsLen 10752 -prefMapSize 244025 -parentBuildID 20201112153044 -appdir /usr/lib/firefox/browser 3305 true tab
Terminando processos com kill
e pkill
kill
envia um sinal paras os processos cujos PID foram especificados.
O sinal padrão TERM
sinaliza o término de um processo. Com esse sinal o processo pode opcionalmente terminar alguma tarefa antes de encerrar sua execução.
kill 41708 41537
⚠️ Apenas o usuário dono do processo e root podem enviar sinais para o processo.
Outros sinais podem ser especificados com a opção -<sinal>
ou -s
. O sinal KILL
extermina o processo. Particularmente útil caso o processo esteja irresponsivo e não é encerrado com o sinal TERM
.
kill -KILL 38618
Quando um processo é terminado ou morto, todos os processos descendentes também são.
pkill
envia um sinal para os processos cujos nomes correpondem ao padrão. pkill
é descrito na mesma página de manual que pgrep
e compartilha de quase todas as suas opções.
Abaixo, pkill
mata todos os processos cujo nome contém firefox
ou brave
.
pkill -f -KILL "firefox|brave"
Suspendendo e retomando processos
Um processo suspenso ou parado, como o nome indica, não faz nada. P. ex., processos com interface gráfica suspensos ficam irresponsivos, como se estivessem congelados.
Processos podem ser suspensos de duas formas: enviando o sinal TSTP
de outra sessão com o comando kill
ou da mesma sessão pressionando Ctrl
+ Z
.
Uma vez que o processo é suspenso, ele passa a ser considerado um job.
O script numeracao
abaixo exibe o PID, e então os números de 0 até 20, pausando por 2 segundos entre cada um deles. Ele será utilizado nos exemplos desta subseção.
#!/usr/bin/env bash
echo "Meu PID $$"
for i in {0..20}
do echo "$i"
sleep 2
done
A permissão de execução do script é concedida ao usuário atual.
chmod u+x numeracao.sh
Suspendendo processos
Execute o script e pressione Ctrl
+ Z
para enviar o sinal TSTP
.
./numeracao.sh
Meu PID 42535
0
1
^Z
[1]+ Stopped ./numeracao.sh
Ao pressionarmos Ctrl
+ Z
a exibição dos números é suspensa e duas linhas adicionais são exibidas. Na primeira, ^Z
indica que Ctrl
+ Z
foi pressionado. Na segunda [1]
indica o número do job que o processo recebeu, Stopped
indica que o comando ./numeracao.sh
foi parado/suspenso.
Execute o script novamente.
./numeracao.sh
Meu PID 42597
0
1
2
Agora, inicie um outro terminal e execute kill
com o PID que aparecer na saída anterior.
#Terminal 2
kill -TSTP 42597
De volta ao primeiro terminal, temos a saída abaixo. O processo 42597
é atribuído ao job [2]
.
Meu PID 42597
0
1
2
3
[2]+ Stopped ./numeracao.sh
jobs
lista o status dos jobs na sessão atual. A opção -l
exibe os PIDs.
jobs -l
[1]- 42535 Stopped ./numeracao.sh
[2]+ 42597 Stopped ./numeracao.sh
Retomando processos suspensos com fg
e bg
fg
retoma a execução do job especificado como argumento.
fg 1
./numeracao.sh
3
4
5
^C
Ctrl
+ C
(^C
) foi pressionado para interromper a execução do processo acima.
bg
retoma a execução do job em segundo plano.
Processos postos em segundo plano liberam o primeiro plano, ou seja, a sessão de Bash exibe o prompt indicando que está pronta para receber novos comandos.
A saída de processos em segundo plano é misturada com a saída da sessão atual. Contudo sua entrada estará disconectada, então sinais como Ctrl
+ Z
ou Ctrl
+ C
não serão recebidos.
bg 2
Na saída abaixo, o prompt é exibido entre a saída do processo retomado. O comando pwd
é digitado e executado, tem sua saída exibida, e Bash exibe novamente o prompt. Ao mesmo tempo o processo em segundo plano continua a exibir os números.
[2]+ ./numeracao.sh &
4
caio@FX505DV:~/temp$ 5
6
7
pwd
/home/caio/temp
caio@FX505DV:~/temp$ 8
9
10
11
12
Cronometrando processos com time
time
executa o comando especificado como argumento, exibe sua saída e então exibe o tempo real até o processo ser encerrado real
, o tempo que o processador tomou para executar o comando user
e o tempo gasto no núcleo do SO sys
.
time pgrep -fo firefox
42288
real 0m0.118s
user 0m0.103s
sys 0m0.012s
O comando abaixo, enviado como argumento de time
, não tem saída.
time for i in {1..1000000}; do :; done
real 0m1.545s
user 0m1.523s
sys 0m0.019s
Analisando propriedades do processo
Cada processo que não é uma thread tem um diretório próprio com subdiretório e arquivos virtuais que estão sob o diretório /proc/<PID>
.
ls -halt /proc/5349
total 0
-r--r--r-- 1 caio caio 0 Dec 4 14:10 arch_status
dr-xr-xr-x 2 caio caio 0 Dec 4 14:10 attr
-rw-r--r-- 1 caio caio 0 Dec 4 14:10 autogroup
-r-------- 1 caio caio 0 Dec 4 14:10 auxv
-r--r--r-- 1 caio caio 0 Dec 4 14:10 cgroup
--w------- 1 caio caio 0 Dec 4 14:10 clear_refs
-rw-r--r-- 1 caio caio 0 Dec 4 14:10 comm
-rw-r--r-- 1 caio caio 0 Dec 4 14:10 coredump_filter
-r--r--r-- 1 caio caio 0 Dec 4 14:10 cpu_resctrl_groups
-r--r--r-- 1 caio caio 0 Dec 4 14:10 cpuset
-r-------- 1 caio caio 0 Dec 4 14:10 environ
dr-x------ 2 caio caio 0 Dec 4 14:10 fdinfo
-rw-r--r-- 1 caio caio 0 Dec 4 14:10 gid_map
-r-------- 1 caio caio 0 Dec 4 14:10 io
-r--r--r-- 1 caio caio 0 Dec 4 14:10 limits
-rw-r--r-- 1 caio caio 0 Dec 4 14:10 loginuid
dr-x------ 2 caio caio 0 Dec 4 14:10 map_files
-rw------- 1 caio caio 0 Dec 4 14:10 mem
-r--r--r-- 1 caio caio 0 Dec 4 14:10 mountinfo
-r--r--r-- 1 caio caio 0 Dec 4 14:10 mounts
-r-------- 1 caio caio 0 Dec 4 14:10 mountstats
dr-xr-xr-x 59 caio caio 0 Dec 4 14:10 net
-r--r--r-- 1 caio caio 0 Dec 4 14:10 numa_maps
-rw-r--r-- 1 caio caio 0 Dec 4 14:10 oom_adj
-r--r--r-- 1 caio caio 0 Dec 4 14:10 oom_score
-rw-r--r-- 1 caio caio 0 Dec 4 14:10 oom_score_adj
-r-------- 1 caio caio 0 Dec 4 14:10 pagemap
-r-------- 1 caio caio 0 Dec 4 14:10 patch_state
-r-------- 1 caio caio 0 Dec 4 14:10 personality
-rw-r--r-- 1 caio caio 0 Dec 4 14:10 projid_map
-rw-r--r-- 1 caio caio 0 Dec 4 14:10 sched
-r--r--r-- 1 caio caio 0 Dec 4 14:10 schedstat
-r--r--r-- 1 caio caio 0 Dec 4 14:10 sessionid
-rw-r--r-- 1 caio caio 0 Dec 4 14:10 setgroups
-r--r--r-- 1 caio caio 0 Dec 4 14:10 smaps
-r--r--r-- 1 caio caio 0 Dec 4 14:10 smaps_rollup
-r-------- 1 caio caio 0 Dec 4 14:10 stack
-r--r--r-- 1 caio caio 0 Dec 4 14:10 statm
-r-------- 1 caio caio 0 Dec 4 14:10 syscall
-rw-r--r-- 1 caio caio 0 Dec 4 14:10 timens_offsets
-r--r--r-- 1 caio caio 0 Dec 4 14:10 timers
-rw-rw-rw- 1 caio caio 0 Dec 4 14:10 timerslack_ns
-rw-r--r-- 1 caio caio 0 Dec 4 14:10 uid_map
-r--r--r-- 1 caio caio 0 Dec 4 14:10 wchan
dr-x--x--x 2 caio caio 0 Dec 4 14:03 ns
dr-xr-xr-x 3 caio caio 0 Dec 4 14:03 task
-r--r--r-- 1 caio caio 0 Dec 4 12:16 cmdline
-r--r--r-- 1 caio caio 0 Dec 4 12:16 status
lrwxrwxrwx 1 caio caio 0 Dec 4 11:47 cwd -> /home/caio
lrwxrwxrwx 1 caio caio 0 Dec 4 11:47 exe -> /usr/bin/bash
-r--r--r-- 1 caio caio 0 Dec 4 11:47 maps
lrwxrwxrwx 1 caio caio 0 Dec 4 11:47 root -> /
dr-xr-xr-x 9 caio caio 0 Dec 4 11:45 .
dr-x------ 2 caio caio 0 Dec 4 11:45 fd
-r--r--r-- 1 caio caio 0 Dec 4 11:45 stat
dr-xr-xr-x 367 root root 0 Dec 4 11:02 ..