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

  1. Listando processos com ps
  2. Filtrando processos com pgrep
  3. Terminando processos com kill e pkill
  4. Suspendendo e retomando processos
  5. Cronometrando processos com time
  6. Analisando propriedades do processo

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 ..
Escrito por Caio Santesso.

Comentários

  • Conteúdo dos posts, exceto onde indicado contrário, licenciado sob a licença CC BY-SA 4.0 .