2.7.2. Control de procesos

linux es un sistema operativo multitarea, esto es, capaz de ejecutar varios programas en paralelo. Al hilo de este asunto, cabe hacer una serie de definiciones:

Proceso

Se denomina proceso, simplemente, a un programa que está en ejecución. Cada procesos tiene una serie de propiedades que definen su estado. Una de ellas, muy importante es el PID.

PID (Process IDentifier)

Es el número asociada a un proceso que lo identifica de manera inequívoca. Esto implica que es único.

Demonio (servicio en la terminología de los sistemas windows)

Es un proceso que se ejecuta en segundo plano, es decir, que se ejecuta sin que intervenga en su ejecución de manera interactiva el usuario.

Prioridad

Es la preferencia que el sistema le da a la ejecución de un proceso. Está representada por un número entre -20 (máxima prioridad) y 19 (mínima prioridad). La prioridad normal es 0.

Bajo este epígrafe trataremos el modo de conocer cuáles son los procesos que ejecuta el sistema, qué recursos consumen, cómo cancelarlos o como traerlos a primer plano y mandarlos a segundo plano. La gestión de los demonios, por ser más un asunto de servidor, se dejará para más adelante.

2.7.2.1. Consulta

ps

Permite obtener información sobre los procesos que se ejecutan en el sistema. Hay dos modos de pasarle opciones: siguiendo el estilo BSD, en que las opciones no van precedidas de guión; y siguiendo el estilo unix, en que son precedidas por uno. Por coherencia con el resto de comandos, usaremos este segundo método[1].

El modo más elemental de uso es aquel que muestra todos los procesos:

$ ps -e
 PID TTY          TIME CMD
[...]
518 ?        00:00:00 ntpd
520 ?        00:00:00 samba
522 ?        00:00:00 samba
523 ?        00:00:00 samba
524 ?        00:00:00 samba
525 ?        00:00:00 samba
526 ?        00:00:00 smbd
527 ?        00:00:00 samba
528 ?        00:00:00 samba
529 ?        00:00:00 samba
530 ?        00:00:00 samba
531 ?        00:00:00 samba
532 ?        00:00:00 winbindd
533 ?        00:00:00 samba
534 ?        00:00:00 samba
535 ?        00:00:00 samba
536 ?        00:00:00 samba
541 ?        00:00:00 smbd-notifyd
542 ?        00:00:00 cleanupd
544 ?        00:00:00 winbindd
545 ?        00:00:00 lpqd
[...]

o bien todos los procesos que están asociados a una terminal:

$ ps -a
 PID TTY          TIME CMD
3068 pts/1    00:00:06 vim
3913 pts/0    00:00:00 tmux: client
4354 pts/5    00:00:00 su
4368 pts/5    00:00:00 bash
5490 pts/4    00:00:00 vim
5654 pts/7    00:00:00 su
5667 pts/7    00:00:00 bash
5672 pts/3    00:00:00 ps

En la salida se observan entre otros el PID del proceso, la terminal asociada y el ejecutable que lo originó. Puede obtenerse un formato largo que da más información con -f:

$ ps -ef
[...]
ntp        518     1  0 11:08 ?        00:00:00 /usr/sbin/ntpd -p /var/run/ntpd.pid -g -u 107:111
root       520     1  0 11:08 ?        00:00:00 /usr/sbin/samba
root       522   520  0 11:08 ?        00:00:00 /usr/sbin/samba
root       523   520  0 11:08 ?        00:00:00 /usr/sbin/samba
root       524   520  0 11:08 ?        00:00:00 /usr/sbin/samba
root       525   520  0 11:08 ?        00:00:00 /usr/sbin/samba
root       526   522  0 11:08 ?        00:00:00 /usr/sbin/smbd -D --option=server role check:inhibit=yes --foreground
root       527   520  0 11:08 ?        00:00:00 /usr/sbin/samba
root       528   520  0 11:08 ?        00:00:00 /usr/sbin/samba
root       529   520  0 11:08 ?        00:00:00 /usr/sbin/samba
root       530   520  0 11:08 ?        00:00:00 /usr/sbin/samba
root       531   520  0 11:08 ?        00:00:00 /usr/sbin/samba
root       532   531  0 11:08 ?        00:00:00 /usr/sbin/winbindd -D --option=server role check:inhibit=yes --foreground
root       533   520  0 11:08 ?        00:00:00 /usr/sbin/samba
root       534   520  0 11:08 ?        00:00:00 /usr/sbin/samba
root       535   520  0 11:08 ?        00:00:00 /usr/sbin/samba
root       536   520  0 11:08 ?        00:00:00 /usr/sbin/samba
root       541   526  0 11:08 ?        00:00:00 /usr/sbin/smbd -D --option=server role check:inhibit=yes --foreground
root       542   526  0 11:08 ?        00:00:00 /usr/sbin/smbd -D --option=server role check:inhibit=yes --foreground
root       544   532  0 11:08 ?        00:00:00 /usr/sbin/winbindd -D --option=server role check:inhibit=yes --foreground
root       545   526  0 11:08 ?        00:00:00 /usr/sbin/smbd -D --option=server role check:inhibit=yes --foreground
[...]

Los procesos derivan unos de otros, de manera que un proceso tiene un proceso padre. SI se quiere observar esta jerarquía de permisos puede usarse la opción -H:

$ ps -eH
[...]
518 ?        00:00:00   ntpd
520 ?        00:00:00   samba
522 ?        00:00:00     samba
526 ?        00:00:00       smbd
541 ?        00:00:00         smbd-notifyd
542 ?        00:00:00         cleanupd
545 ?        00:00:00         lpqd
523 ?        00:00:00     samba
524 ?        00:00:00     samba
525 ?        00:00:00     samba
527 ?        00:00:00     samba
528 ?        00:00:00     samba
529 ?        00:00:00     samba
530 ?        00:00:00     samba
531 ?        00:00:00     samba
532 ?        00:00:00       winbindd
544 ?        00:00:00         winbindd
533 ?        00:00:00     samba
534 ?        00:00:00     samba
535 ?        00:00:00     samba
536 ?        00:00:00     samba
[...]

Alternativa a la opción -H es --forest, con la que obtenemos una salida más vistosa y elocuente:

$ ps -e --forest
[...]
518 ?        00:00:00 ntpd
520 ?        00:00:00 samba
522 ?        00:00:00  \_ samba
526 ?        00:00:00  |   \_ smbd
541 ?        00:00:00  |       \_ smbd-notifyd
542 ?        00:00:00  |       \_ cleanupd
545 ?        00:00:00  |       \_ lpqd
523 ?        00:00:00  \_ samba
524 ?        00:00:00  \_ samba
525 ?        00:00:00  \_ samba
527 ?        00:00:00  \_ samba
528 ?        00:00:00  \_ samba
529 ?        00:00:00  \_ samba
530 ?        00:00:00  \_ samba
531 ?        00:00:00  \_ samba
532 ?        00:00:00  |   \_ winbindd
544 ?        00:00:00  |       \_ winbindd
533 ?        00:00:00  \_ samba
534 ?        00:00:00  \_ samba
535 ?        00:00:00  \_ samba
536 ?        00:00:00  \_ samba
[...]

También hay formas de filtrar los procesos mostrados según distintos criterios. Por ejemplo, para elegir los de un determinado usuario:

$ ps -u josem

o elegir procesos por nombre:

$ ps -C systemd

o por PID[2]:

$ ps 1000

o mostrar los procesos de un determinado padre. Para ello se debe indicar el PID del proceso padre:

$ ps --ppid 1579

ps permite incluir varias opciones de filtrado:

$ ps -C bash -u josem

incluso varias veces la misma opción:

$ ps -C bash -C system

pero nunca acomulan el efecto de filtrado, sino el resultado. Es decir, en el ejemplo:

$ ps -C bash -u josem

no devuelve los procesos de bash que esté ejecutando el usuario «josem», sino cualquier proceso de bash (sea o no de «josem») más cualquier proceso que pertenezca a «josem» (sea de bash o de cualquier otro programa). En el segundo ejemplo:

$ ps -C bash -C system

la orden devuelve cualquier proceso de bash o de systemd. Cuando el criterio es el mismo también se puede usar esta alternativa:

$ ps -C systemd,bash

Advertencia

Tenga presente que si quiere que los criterios de filtrado sean acomulativos, esto es, que el resultado cumpla ambos criterios, tendrá que recurrir a pgrep.

También se puede definir exactamente qué campos se quieren obtener mediante la opción -o seguida de los nombres de los campos (véase la página del manual ps). Por ejemplo, esto mostraría para todos de los procesos el nombre del usuario que lo ejecuta, el pid, el ppid y el ejecutable:

$ ps -eo user=,pid=,ppid=,comm=

El signo igual, indica que no se desea que ps incluya para el campo cabecera. Si todos los campos incluyen un igual, entonces no habrá cabecera alguna.

Se pueden también ordenar los resultados con -sort:

$ ps -eo user=,pid=,ppid=,comm= --sort ppid,pid
pstree

Muestra los procesos del sistema en forma de árbol, tal como hace el comando tree con los directorios y ficheros. Para constituir este árbol debe saber que todo proceso tiene un proceso padre del que deriva. Por ejemplo, si en una sesión de bash ejecutamos este comando pstree, el proceso correspondiente a éste es hijo del proceso de bash.

pgrep

Permite obtener el PID de un proceso atendiendo a distintos criterios. Su uso más sencillo es obtener los PID asociado al nombre de un programa. Por ejemplo, esto devolvería todos los procesos que se corresponden con sesiones de bash:

$ pgrep bash
2966
3004
3084
3588
3811
3967
4368
4546
5529

Puede no indicarse el nombre del programa, en cuyo caso se entenderá que deseamos el de cualquier programa, o bien, utilizar una expresión regular que nos permitirá hacer búsquedas más poderosas. Por ejemplo, esta búsqueda:

$ pgrep 'sh$'

nos devolverá los PID de todos los procesos cuyo nombre de programa acabe en «sh».

Advertencia

En realidad el argumento de pgrep es simplemente un patrón expresado en forma de expresión regular extendida, incluso en el primer ejemplo:

$ pgrep bash

Por tanto, este primer ejemplo no devuelve los PID de los procesos de bash, sino los PID de cualquier programa que dentro de su nombre incluya la cadena «bash».

En principio, la concordancia se realiza únicamente con el nombre del proceso, pero puede buscarse concordancia con la orden completa (que incluye parámetros) utilizando la opción -f. Por ejemplo:

$ pgrep -f 'systemd.*user'
937523

concordaría con procesos de systemd propios de usuarios:

$ pgrep -af 'systemd.*user'
937523 /lib/systemd/systemd --user

Para filtrar los resultados podemos añadir opciones que fija criterios adicionales. Por ejemplo:

$ pgrep -u usuario
1223
1300
1311
1328
1380
1387

permite obtener los PID de todos los procesos (no hemos indicado qué programa) que pertenezcan al usuario de nombre «usuario». O bien:

$ pgrep -P 1114
1116
2602

devuelve los procesos cuyo proceso padre es el proceso 1114.

A diferencia de ps los criterios de filtro son acumulativos, por lo que si se utilizan varios, pgrep sólo devolverá aquellos que cumplan con todos. En consecuencia:

$ pgrep -u usuario bash

devolverá los procesos de bash a nombre del usuario «usuario». Además, debe tenerse en cuenta que en las opciones (pero no en el patrón que debe ser único), pueden indicarse varios criterios a la vez:

$ pgrep -u usuario,root bash

que devolverá los procesos de bash a nombre de «usuario» o «root».

Otra opción interesante es -c que en vez de devolver los PID de los procesos, devuelve cuántos procesos en total. Por tanto, pasa saber cuántos procesos está ejecutando el usuario «usuario»:

$ pgrep -cu usuario
6

Lamentablemente, pgrep sólo devuelve el PID (y la orden completa con -a) y no una información tan completa y configurable como ps.[3]

top

Permite observar los procesos en tiempo real:

$ top
htop

Es una aplicación que mejora la interfaz de top:

$ htop

Es probable que no esté incluida en la instalación base y requiera su instalación explícita.

uptime

Muestra el tiempo trascurrido desde el arranque. el número de usuarios conectados y la carga media del sistema en el último minuto, los cinco últimos minutos y los quince últimos minutos:

$ uptime
00:07:44 up 116 days, 12:15,  2 users,  load average: 0,00, 0,03, 0,09

Tiene algunas opciones. Con -s da una respuesta muy parecida a who con la opción -b:

$ uptime -s
2016-09-09 12:52:12
time

Permite conocer el tiempo que tarda una orden en completarse:

$ time sleep 2

real    0m2.009s
user    0m0.004s
sys     0m0.000s

real es el tiempo trascurrido desde que comenzó la orden hasta que se completo. user el tiempo de CPU fuera del kernel empleado y sys el tiempo de CPU dentro del kernel empleado. Por tanto, la suma de las dos últimas cantidad indica el tiempo total de CPU empleada.

2.7.2.2. Manipulación

Ya se ha explicado cómo dar órdenes. Una orden provoca la creación de un proceso durante un determiando tiempo. Ahora bien, es posible modificar la forma en que se da la orden para lograr distintos fines.

nice

Modifica la prioridad de un proceso. Cuando se ejecuta una orden, la prioridad del proceso es 0. Sin embargo, nice permite cambiar esta prioridad. Para usuarios distintos del administrador sólo se puede disminuir la prioridad, es decir, dar valores positivos.

Para usar nice basta con anteponerlo al proceso que se quiere ejecutar. Por ejemplo:

$ nice ffmpeg -i input.wmv -s hd720 -c:v libx264 -crf 23 -c:a aac -strict -2 output.mp4

recodifica una película en calidad HD720, haciendo que para este proceso bastante costoso disminuya la prioridad. Cuando nice se usa sin indicar la prioridad, se supone que esta es 10. Puede especificarse la prioridad exacta con la opción -n:

$ nice -n10 ffmpeg [...]

Valores negativos hace el proceso más prioritario de lo normal, pero deben adjudicarse como root.

renice

Modifica la prioridad de un proceso ya comenzado. Para seleccionar este proceso necesitamos el pid del mismo, el cual podemos obtener a traves de ps, por ejemplo. Suponiendo que sea el 5789:

$ renice -n 10 -p 5789
kill

Envía señales a los procesos, muy comúnmente para acabar con ellos, de ahí su nombre. Hay una larga lista de señales que pueden obtenerse mediante la opción -L:

$ kill -L
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX

Las más usadas para acabar procesos son:

SIGTERM (15)

Que le indica al proceso que haga un apagado suave e intente cerrar antes todo los recursos que tenga abiertos. Es el apagado más recomentable, aunque no siempre funciona, sobre todo si el proceso tiene algún hijo. Es el apagado que kill, pkill o killall intentan por defecto si no se especifica otro concreto.

SIGHUP (1)

HUP proviene de hang up, esto es, colgar y es la señal que recibían los programas cuando en accesos remotos por conexión serie el usuario decide colgar. En sistemas modernos este acceso no es tan común y la señal se ha reciclado y significa que la terminal dentro de la que corre el programa se ha cerrado. En bastantes programas interactivos la señal puede tener el efecto de un apagado suave como SIGTERM, pero en los demonios, que como no son interactivos, no suelen ejecutarse en una terminal, es común que se interprete como que es necesario volver a leer la configuración y, en consecuencia, el programa no acabe. Por tanto, si nuestra intención es acabar un proceso de forma suave, es más recomendable la opción anterior.

SIGINT (2)

Acaba taxativamente el proceso, aunque éste puede no hacer caso a la señal. Equivale a Ctrl+C sobre un proceso en primer plano.

SIGKILL (9)

Provoca el apagado obligatorio, por lo que, aunque tiene las mismas consecuencias de la señal anterior (puede quedar algo abierto), la señal no puede ser obviada por el proceso.

Lo habitual, cuando se intenta acabar manualmente con un proceso, es intentar el apagado suave (SIGTERM) y, si este no es posible, intentar el apagado forzoso (SIGKILL). Por tanto, si quisiéramos acabar con los procesos de PID 1037 y 1000, haríamos:

$ kill 1897 1000

o bien:

$ kill -15 1897 1000

que es lo mismo. Y, si esto no funciona, no tendremos más remedio que hacer:

$ kill -9 5675 6676

Nota

En ocasiones, es imposible acabar del todo con un proceso ni aun con la señal SIGKILL (9). En estos casos, el proceso acaba en un estado zombi por tiempo indefinido, que se nota con un Z al consultar el proceso con ps.

SIGTSTP (20)

Suspende el proceso, esto es, lo deja en estado «Suspendido» a la espera de que otra orden de usuario vuelva a ponerlo en ejecución. Equivale a Ctrl+Z sobre un proceso en primer plano.

SIGSTOP (19)

Como el anterior, pero la parada es más agresiva. Es preferible la orden anterior.

SIGCONT (18)

Reanima un proceso suspendido.

El uso de kill es bastante sencillo:

$ kill -SEÑAL PID1 PID2 ...

o sea, se indica la señal y se indican la relación de PID correspondientes a los procesos a los que se quiere enviar la señal. Para expresar la señal podemos usar el número (p.e. 9), su nombre (p.e. SIGKILL) o su nombre abreviado (p.e. KILL).

Advertencia

kill es una orden interna del intérprete, por lo que depende de este. Usar el nombre completo (SIGKILL) funciona en la versión de bash, pero no en dash

También es posible utilizar en vez del PID del proceso, su identificador de trabajo en la sesión (véase jobs), pero antecediéndolo con un «%»:

$ sleep 1000 &
[1] 12699
$ jobs
[1]+  Ejecutando              sleep 1000 &
$ kill -TSTP 12699
$ jobs
[1]+  Detenido                sleep 1000
$ kill -CONT %1
$ jobs
[1]+  Ejecutando              sleep 1000 &
pkill

Es una orden que, como kill, permite enviar señales a los procesos, pero para cuya selección se usa la sintaxis de pgrep. Por tanto, podremos referirlos mediante su nombre (no su PID) añadiendo criterios acomulativos de selección como con pgrep, y además, indicar qué señal enviar como con kill:

# pkill -15 -uroot bash
killall

Cancela procesos identificándolos por su nombre. Pueden usarse las señales indicadas anteriormente. Por ejemplo, esto cancela de forma suave todas las sesiones de bash abiertas que pueda cancelar quien lo ejecuta:

$ killall bash

Tiene opciones (-u, -g, etc.) para ser más específico, pero no dispone de tantas como pkill.

Advertencia

killall es parte del paquete psmisc, que puede no encontrarse instalado por defecto.

Por lo general, cuando se ejecuta una orden, la shell espera hasta que esta haya acabado para liberar la línea de comandos. Esto es debido a que la orden se ejecuta en primer plano. Arrancada de este modo, podemos escribir Ctrl+C para cancelar la orden tal como haríamos con kill; pero también podemos escribir Ctrl+Z para detener la orden. Si hacemos esto segundo, la orden deja de ejecutarse, pero no están cancelada: simplemente queda a la espera de que demos la orden de proseguir. Por ejemplo, supongamos que hacemos una cuenta de 1 a 10 esperando un segundo entre número y número:

$ (for i in {1..10}; do sleep 1; echo $i; done)
1
^Z
[1]+  Detenido                ( for i in {1..10};
jobs (orden interna de la shell)

Permite consultar la lista de trabajos activos en la sesión actual:

$ jobs
[1]+  Detenido                ( for i in {1..10};

Por tanto, hay una tarea detenida. Si deseamos que prosiga, hay dos posibilidades: que mandemos que se ejecute en primer plano…

fg (orden interna de la shell)

Manda una tarea a primer plano (y la activa en caso de que estuviera suspendida). Para referirse a ella se debe especificar el número de trabajo que proporciona jobs:

$ fg %1
2
3
...
10
$

Nota

Para refefir el proceso por su PID en vez de por su número de trabajo debe antecederse el número con # en vez de con %.

o mandamos que se ejecute en segundo plano…

bg (orden interna de la shell)

Manda una tarea a segundo plano. Para referirse a ella se debe especificar el número de trabajo que proporciona jobs:

$ bg %1

Es posible también ejecutar una tarea en segundo plano acabando la orden con un &:

$ sleep 60 &
[1] 15991
$ jobs
[1]+  Ejecutando              sleep 60 &

2.7.2.3. Ejercicios sobre gestión de procesos

  1. Mostrar los procesos ejecutados por el usuario «usuario».

  2. Mostrar:

    1. las shells que se están ejecutando en el sistema.

    2. Lo mismo, pero sólo aquellas que ejecutan el usuario «usuario» (en este segundo casa, basta con indicual cuáles son los PID)

  3. Mostrar todos los procesos ordenados por uso de la CPU.

  4. Mostrar todos los procesos indicando el PID, el UID del propietario, la memoria utilizada, la prioridad y el comando completo.

  5. ¿Cúantos procesos tiene corriendo en el sistema el usuario «usuario»?

  6. ¿Desde cuándo lleva encencida la máquina?

  7. Ejecutar el comando sleep 1000, suspenderlo y ponerlo a trabajar en segundo plano; volverlo a traer a primer plano y, por último, cancelarlo

  8. Ejecutar el comando sleep 1000, suspenderlo, ponerlo a trabajar en segundo plano y, sin traerlo a primer plano, acabar con él.

  9. Indicar qué tiempo tarda el ordenador en buscar dentro del directorio de configuraciones el fichero dhclient.conf.

  10. La orden:

    $ programa_muy_pesado
    

    tarda mucho en ejcutarse y consume mucho procesamiento, y hace que la película que estamos viendo mientras esperamos a que se complete, vaya a tirones. ¿Cömo puedo ejecutarla para poder ver la película sin problemas?

Notas al pie