Tareas y Procesos
Tareas y Procesos
Tareas y Procesos
En este punto tendremos que empezar a determinar que es un proceso y una tarea. Anteriormente dijimos que un programa se transformaba en proceso en el momento en que este se ejecutaba y estaba en memoria. Adems del nombre que el proceso recibe, que es el nombre del programa que esta corriendo, recibe tambin un nmero identificativo llamado PID (process ID, o ID de proceso). Si ejecutamos el comando ps veremos los procesos que estn ejecutando en este momento con nuestro UID, es decir que estamos corriendo nosotros mismos
[shrek@pantano:~]$ ps PID TTY STAT TIME COMMAND 172 p0 S 0:00 -bash 184 p0 R 0:00 ps [shrek@pantano:~]$
Se puede ver que estn corriendo dos procesos, el bash (que es el intrprete de comandos) y el proceso ps que es el que estamos usando en este momento en una terminal determinada. Como se puede ver el primer nmero es el PID que el sistema le asigna al proceso y en la columna COMMAND se puede ver el nombre del proceso. De ninguna manera estos son todos los procesos que se estn ejecutando en el sistema. Si se quisieran ver todos los procesos tendran que poner ps -ax con lo que obtendran un listado con todos los procesos que se estn ejecutando. Como se puede apreciar, estn ambos procesos ejecutndose al mismo tiempo, pero solo uno de ellos esta activo, el comando ps. Nos podemos dar cuenta de esto ya que en la columna STAT aparece en la lnea del bash la letra S de SLEEP, ya que en ese momento el intrprete de comandos esta esperando a que el proceso ps termine. Y es aqu donde esta la diferencia entre proceso y tarea. Aunque ambos son procesos, una tarea se refiere al proceso que esta corriendo. Este calificativo solo lo da el shell del sistema cuando se utilizan los controles de tareas dado que no todos los intrpretes de comandos soportan este tipo de control.
Esto nos mostrara una lista bastante larga de archivos por pantalla y nos quedaramos sin el control del intrprete de comandos mientras esta ejecutndose. Podramos usar el dispositivo null, que si recuerdan era como un agujero negro donde todo lo que se enviaba a l desapareca, para redirigir la salida y que no saliera por pantalla
[shrek@pantano~]$ find / -name "*" > /dev/null
Igualmente as no contaramos con la atencin de nuestro interprete de comandos hasta que terminara el trabajo el comando find. La forma de tener la atencin del shell inmediatamente despus de lanzar el proceso find es envindolo en segundo plano
[shrek@pantano:~]$ find / -name "*" > /dev/null & [1] 192 [shrek@pantano:~]$
Como se aprecia, regres de inmediato al shell, pero antes envi un mensaje a la terminal. El [1] representa a un nmero de trabajo que el shell asigna a cada uno de los procesos que pasa a segundo plano. Inmediatamente despus vemos el nmero de PID del proceso. Podremos identificar al proceso por cualquiera de los dos nmeros mientras se encuentre en segundo plano. Para ver cuantos trabajos estn ejecutndose en este momento podemos usar el comando jobs.
[shrek@pantano:~]$ jobs [1]+ Running [shrek@pantano:~]$ find / -name "*" >/dev/null &
Podremos eliminar un proceso que se esta ejecutando con la ayuda del comando kill seguido bien sea del nmero de trabajo precedido de un signo % o del nmero de PID. De esta forma estamos matando al proceso pero puede darse el caso de que este tarde en desaparecer dado que tiene que limpiar el entorno, por esto muchas veces parecer que no nos a hecho caso. En realidad el proceso esta haciendo una limpieza del sistema evitando as el mal funcionamiento del mismo y/o una inconsistencia en los datos con que trabajaba. Como ejemplo usaremos otro comando muy tpico, el comando yes. Este comando enviar a la salida estndar continuamente la letra y. Sirve este comando para que en caso de que se requiera contestar afirmativamente a las peticiones de un programa pudiremos mediante una redireccin contestarle con un y a cada pregunta. Si lo ejecutramos sin redirigir la salida a /dev/null, nos llenara la pantalla con una columna infinita de y. Por esto lo enviaremos a segundo plano redirigiendo la salida y luego lo mataremos con el comando kill.
[shrek@pantano:~]$ yes > /dev/null & [1] 201 [shrek@pantano:~]$ kill %1 [shrek@pantano:~]$ jobs [1]+ Terminated yes > /dev/null & [shrek@pantano:~]$
Como podrn ver, en el momento en que se mando el comando kill, no hubo ningn mensaje. Solo despus de ejecutar el comando jobs se nos informo que el trabajo nmero 1 haba finalizado (TERMINATED). Podemos tambin hacer lo mismo empleando el nmero de PID con lo que obtendremos idnticos resultados.
Como pueden ver, el proceso que se envi a segundo plano todava se esta ejecutando (Running), en cambio la que se mando dormir estaparada esperando que la relancemos (Stopped). Para ponerlo en primerplano o despertarlo a cualquiera de los dos podemos usar el signo "%"seguido del nmero del proceso o bien el comando fg.
[shrek@pantano:~]$ %1 yes >/dev/null &
Podremos enviar tambin un comando que esta durmiendo a que ejecute en segundo plano a travs del comando bg
[shrek@pantano:~]$ jobs [1]- Stopped [shrek@pantano:~]$ bg %1 [1]+ yes >/dev/null & [shrek@pantano:~]$ jobs [1]+ Running yes >/dev/null
Cabe decir que tanto fg como bg son comandos internos del intrprete de comando. Esto es as porque es el mismo intrprete quien hace el control de tareas. Puede darse el caso de que existan intrpretes de comandos que no tengan soporte para control de tareas.
ps
Sin ninguna opcin dar la lista de procesos que estn corriendo desde la terminal donde se ejecuto el ps
[shrek@pantano:~]$ ps PID TTY TIME CMD 9648 tty2 00:00:02 bash 9659 tty2 00:00:00 ps [shrek@pantano:~]$
Las columnas que nos quedan por explicar son TTY y TIME. TTY identifica la consola donde se esta ejecutando el proceso. En este caso es una terminal local. La columna TIME nos indica la cantidad de tiempo total que el proceso se ha estado ejecutando. Como se puede ver el tiempo es de 2 segundos. Aunque este horas el sistema encendido, el bash pasa su mayor parte del tiempo esperando que se le envie algn comando para ejecutar, mientras tanto esta esperando dormido. Puede verse en la columna STAT en que estado se encuentra el programa. Por ejemplo, que vemos que el bash en el momento de ejecutarse el comando ps esta dormido (S) y que el proceso ps esta activo (R). Si aadimos la opcin l tendremos un listado largo del comando ps. En algunas versiones se usa la opcin -l
[shrek@pantano:~]$ ps l F UID PID PPID PRI 4 100 9648 1 9 4 100 9660 9648 17 NI 0 0 VSZ RSS WCHAN STAT TTY 4368 1400 11b1d0 S tty2 2676 732 - R tty2 TIME COMMAND 0:01 -bash 0:00 ps l
Dentro de esta informacin esta la columna del UID que identifica el dueo del proceso. El PID del proceso y tambin el PPID que es el PID del proceso padre. Podemos apreciar que el padre del comando ps l es el -bash. NI viene de nice y es un nivel que se otorga a un proceso para requerir cierto privilegio. En este caso tiene uno muy bajo por ende un proceso que tenga un valor mayor tendr ms tiempo de procesador para trabajar. SIZE es el tamao que tiene el proceso. RSS es la tamao del proceso que se encuentra residente en la memoria. WCHAN es el nombre de la funcin del kernel donde el proceso esta durmiendo. Esta expresado en forma hexadecimal. Otra forma en la que podemos ver el padre de cada proceso es a travs del modificador f.
[shrek@pantano:~]$ ps f
top
Ahora bien, el comando ps nos muestra una radiografa de los procesos en el momento, pero no nos muestra los cambios que se van teniendo. Para esto contamos con el comando top. El mismo muestra en tiempo real la situacin de los procesos que se estn ejecutando en el sistema, ordenados por defecto segn el porcentaje la CPU que estn usando. Al ejecutarlo se podr ver otra informacin adicional, como la cantidad de usuarios que estn en el sistema, cuantos procesos estn corriendo y de estos cuantos estas activos, cuantos durmiendo, cuantos en proceso de terminar (ZOMBIE) y cuantos finalizados. Adems se podr ver la cantidad e memoria fsica total, la cantidad usada y la cantidad libre; as como tambin se podr obtener la misma informacin de la memoria swap. Lo ms importante es que esta informacin de ira actualizando automticamente cada tanto tiempo, por defecto 5 segundos, y que podremos ir alterando lo que va mostrando. Por ejemplo podemos hacer que ordene los procesos de acuerdo a la cantidad de memoria que esta usando con solo presionar la tecla M. U ordenarlos de acuerdo al tiempo que llevan corriendo. Otra utilidad es que podramos matar algn proceso con solo presionar la tecla k y luego darle el nmero de PID. El listado que nos mostrar contendr el nmero de PID, el usuario que lo est ejecutando, la prioridad del proceso (PRI), el valor nice (NI), el tamao del proceso (SIZE), el tamao total del proceso junto con los datos que maneja (RSS), el tamao usado por el proceso en la memoria (SHARE), el estado del proceso(STAT), el tamao de las libreras del proceso (LIB), el porcentaje de CPU ( %CPU) y de memoria (%MEM) as como tambin el tiempo de ejecucin (TIME) y el nombre del proceso (COMMAND).
Deberemos saber tambin que con la ayuda solamente de la conjuncin de comandos no podremos hacer script verdaderamente interesantes. Por esto se incorporan las construcciones de shell. Estas son las construcciones while, for-in, if-then-fi y case-esac. Existen muchas ms pero estas sern las ms tiles para nosotros en estos momentos. Para mayor informacin sobre otro tipo de construcciones seria mejor revisar las pginas de manual del intrprete de comandos bash (man bash). Empezaremos viendo un uso sencillo de la construccin for-in que tiene la siguiente sintaxis
for var in word1 word2 do commandos done
Para poder usar esto, podramos realizar una lista de directorios que querramos nosotros de una sola vez
for dir in /bin /etc /lib do ls -R $dir done
Esto har un listado recursivo 3 veces. La primera vez que pase por el ciclo, la variable $dir tomar el valor /bin, la segunda ser /etc y la tercera /lib. Podramos prescindir del par do-done con el uso de llaves ({})
for dir in /bin /etc /lib { ls -R $dir }
Ya hemos visto anteriormente la idea de argumentos en la utilizacin de comandos y programas; pero deberemos ver como se realiza la codificacin de un script para tomar estos argumentos. Como antes dijimos, los argumentos eran pasados a los programas para que estos lo utilizaran. En la construccin de script veremos lo que se llaman variables posicionales cuyo valor corresponde a la posicin del argumento luego del nombre del script. Supongamos que tenemos un script que toma 3 argumentos. El primero ser el nombre de un directorio, el segundo el nombre de un archivo y el tercero es una palabra a buscar. Este script buscar en todos los archivos del directorio, cuyo nombre incluya el nombre de archivo que le pasamos como argumento, la palabra que tambin le estamos pasando. El script se llamara miscript y estar compuesto del siguiente cdigo
ls $1 | grep $2 | while read ARCHIVO do grep $3 ${1}/${ARCHIVO} done
La sintaxis ser
miscript [directorio] [nombre_archivo] [palabra] Aqu tenemos varias cosas para ver. Primero que nada, el uso de las variables posicionales. Como se podr apreciar el nmero de la variable, que esta precedido por un signo $, indica la posicin del argumento cuando el script es llamado. Solamente se podrn usar 9 variables de este tipo sin tener que emplear un pequeo truco de corrimiento que veremos luego, dado que el 0 representa al nombre del script mismo. Es decir que en este caso la variable posicional $0 valdr "miscript". Como se puede ver se han utilizado canalizaciones para poner ms de un comando junto. Al final de la construccin se esta usando una construccin while. Esta se usa para repetir un ciclo mientras una expresin sea cierta.
while ($VARIABLE=valor) do commandos done
En este caso esta siendo usada al final de una canalizacin con la instruccin read ARCHIVO. Es decir, mientras pueda leer el contenido de la variable $ARCHIVO, continuar. Esta variable $ARCHIVO contiene el resultado de lo que arrojo la canalizacin del listado con la salvedad de que tenia que contener la palabra que le enviamos como argumento, es as que solo se imprimirn las lneas en las que coincida la palabra a buscar de los archivos que cumplan con los requisitos. Otra cosa a tener en cuenta es una nueva construccin en este script, ${1}/${ARCHIVO}. Al encerrar un nombre de variable dentro de llaves podemos combinarlas. En este caso forman el nombre del directorio (${1}) y aadimos una / como separador del directorio, y seguido e nombre del archivo donde se aplicara el comando grep con la palabra a buscar $3. Podramos hacer que este script sea un poco ms documentado. Para esto podramos asignar las variables posicionales a otras variables para que se pueda entender mejor su uso.
DIRECTORIO=$1 ARCHIVO_BUS=$2 PALABRA=$3 ls $DIRECTORIO | grep $ARCHIVO_BUS | while read ARCHIVO do grep $PALABRA ${DIRECTRIO}/${ARCHIVO} done
El nmero de las variables posicionales que pueden usarse en un script, como antes dijimos, se encuentra restringido a 10. Qu pasara si tenemos ms de 9 argumentos? Es aqu donde tenemos que usar la instruccin shift. Esta instruccin mueve los argumentos hacia abajo en la lista de parmetros posicionales. De esta manera podramos tener una construccin con esta distribucin de variables
DIRECTORIO=$1 shift ARCHIVO_BUS=$1
De esta manera podramos asignar el valor de la primer variable posicional a la variable DIRECTORIO y luego el siguiente argumento que habamos dado se tomara otra vez con el nombre de $1. Esto solo tiene sentido si asignamos las variables posicionales a otra variable. Si tuviramos 10 argumentos, el dcimo no estara disponible. Sin embargo, una vez que hacemos el que las variables se corran de posicin este se convertir en el noveno y se acceder por la variable posicional $9. Existe una forma tambin de pasar como argumento a la instruccin shift el nmero de posiciones que queremos correr. Por lo cual podemos usar
shift 9
y as se lograra que el dcimo argumento sea el parmetro posicional 1. Lo que ocurre con los anteriores 9 argumentos es que desaparecen si no se los asigno a una variable anteriormente. Podremos cambiar usar un nuevo parmetro que podr contener mas de un parmetro pasado al script. Este se denomina $* y contendr el resto de los argumentos que se pasen al script luego de que se haya realizado un corrimiento determinado. Por ejemplo, si quisiera buscar una frase en lugar de una nica palabra el script podra ser
DIRECTORIO=$1 ARCHIVO_BUS=$2 shift 2 PALABRAS=$* ls $DIRECTORIO | grep $ARCHIVO_BUS | while read ARCHIVO do grep "$PALABRAS" ${DIRECTRIO}/${ARCHIVO} done
Lo que aqu cambio es que luego de haber asignado a variables los parmetros posicionales 1 y 2 las variables fueron desplazadas dos veces, eliminando los dos primeros argumentos. Luego asignamos los argumentos restantes a la variable PALABRAS. Para que sea tomado como una cadena, se lo encerr entre comillas para ser pasado al comando grep, si no lo hiciramos el bash vera nuestra entrada como argumentos individuales para pasar al grep. Otro parmetro que es de utilidad es el $# que lleva la cuenta de la cantidad de argumentos pasados al script. De esta forma podramos realizar un script que identificara si se le estn pasando la cantidad de parmetros que realmente necesita y anunciar el error si faltaran estos. Para ello utilizaremos la construccin if-then-fi que es muy parecida a la while-do-done, en donde el par if-fi marca el final de un bloque. La diferencia entre estas construcciones es que el if solo evaluara una vez la condicin. La sintaxis es la siguiente
if [ condicin ] then hacer_algo fi
Las condiciones que puede usarse se encuentran en las man page test (man test). Nosotros usaremos una simple condicin para contar argumentos, pero pueden ser
usadas distintas condiciones como nombres de archivos, permisos, si son o no directorios, etc. Para saber si la cantidad de argumentos que se nos a pasado en el script es correcta, utilizaremos una opcin aritmtica que compare la cantidad de argumentos pasados ($#) con un nmero que nosotros estipularemos, en este caso 3. Pueden usarse diferentes opciones con el formato arg1 OP arg2, donde OP ser alguno de los siguientes -eq es igual -ne no es igual -lt menor que -le menor que o igual -gt mayor que -ge mayor que o igual Se usar en este caso el -ge (mayor o igual que) dado que si la cantidad de argumentos que siguen al segundo es mayor la tomaremos como una frase a buscar y si es igual como una palabra. Lo nico que haremos en caso de que la cantidad de argumentos sea menor, ser informar de esto y de la forma de usar el script.
DIRECTORIO=$1 ARCHIVO_BUS=$2 shift 2 PALABRAS=$* if [ $# -ge 3 ] then ls $DIRECTORIO | grep $ARCHIVO_BUS | while read ARCHIVO do grep "$PALABRAS" ${DIRECTRIO}/${ARCHIVO} done else echo "Nmero de argumentos insuficientes" echo "Use: $0 <directorio> <archivo_a_buscar> <palabras>" fi
Otra utilidad para del if, es la posibilidad de realizar lo que se denomina if anidados. De esta forma podramos tener varias capas de if-then-else-fi. Como ejemplo podra ser esta una construccin vlida
if [ $condicion1 = "true" ] then if [ $condicion2 = "true" ] then if [ $condicion3 = "true" ] then echo "las condiciones 1, 2 y 3 son ciertas" else echo "solo son ciertas las condiciones 1 y 2" fi else echo "condicin 1 es cierta, pero no la 2" fi else echo "la condicin 1 no es cierta" fi
Podramos tambin hacer que una sola variable tome diferente valores e interactuar con ella para ver si se cumple la condicin buscada. De esta forma podramos por ejemplo hacer un men de usuario con distintas alternativas. Pero esta forma es til solo para pocas condiciones. Que pasara si tuviramos muchas condiciones mas que agregar? Se nos hara por dems de complicado seguir el esquema armado y sera demasiado cdigo para lo que se trata de realizar. Es aqu es donde se necesita la estructura case-esac. Como se podr ver, al igual que en el if-fi aqu el inverso de case (esac) cierra la construccin. Veamos un ejemplo de una construccin con case
read case a) b) c) *) esac ELECCION $ELECCION in programa1;; programa2;; programa3;; echo "No eligi ninguna opcin valida";;
Hay que tener en cuenta algunas cosas respecto a este tipo de construccin. Por ejemplo el mandato que le damos al principio read indica al bash que tiene que leer lo que se ingrese a continuacin y lo guarde en una variable que se llamara ELECCION. Esto tambin ser til para el uso de otras construcciones ya que el read no es propiedad exclusiva de la construccin esac, sino que pertenece al mismo bash. Como se ve, se le indica que si el valor que la variable contiene es igual a alguna de las mostradas debajo se ejecute determinado programa. (case $ELECCION in). La eleccin se debe terminar con un parntesis ")" para que se cierre las posibilidades. Podramos poner ms posibilidades para cada eleccin; lo nico que hay que recordar es cerrar con un parntesis. El punto y coma nos marca el final de un bloque, por lo que podramos agregar otro comando y se cerrara con punto y coma doble al ltimo. El asterisco del final nos indica que se har en caso de que no coincida lo ingresado con ninguna de las posibilidades. Un ejemplo, sera que nuestra construccin reconozca maysculas y minsculas y adems ejecute ms de un comando por bloque.
read ELECCION case $ELECCION in a|A) programa1 programa2 programa3;; b|B) programa4 programa5;; c|C) programa3;; *) echo "No eligi ninguna opcin valida";; esac
Hay que recordar que todos estos script podrn estar en un archivo, pero para que se ejecuten se le deber primero dar los permisos pertinentes. Un par de cosas a tener en cuenta para la construccin de script son la forma en que se quiere que ejecute ste y la captura de teclas. Al ejecutarse un script de shell, se estar creando un bash hijo que lo ejecutar. Dado que las variables y funciones pertenecen al intrprete de comandos que las cre, al finalizar el script el proceso hijo del bash morir y con el todos los seteos de variables y funciones. Por esto, si se quisiera que los cambios de las variables y las funciones que se definieron permanezcan para ser utilizables una vez que el script haya terminado, se deber comenzar a ejecutar el script con un punto "." seguido por un espacio antes del nombre de ste. De esta forma el proceso del intrprete de comando actual sera quien ejecute el script con lo que se conservaran todas las variables y funciones.
[shrek@pantano:~]$ . miscript
Un script puede dejar cosas sueltas antes de terminar si ste es finalizado bruscamente envindole una seal de finalizacin [1] ya sea con la combinacin de teclas Ctrl-C o con un kill -15. Para esto se debern capturar estas seales para poder hacer una limpieza, ya se de variables o archivos, antes de finalizar. La forma de hacerlo es con el uso del comando trap; de esta forma se capturar la seal que se le enve al script y se podr ya sea ignorar la misma o ejecutar otro comando de limpieza. Para demostrar esto haremos un pequeo script que servir de men. La llamada al script del men podra estar en el archivo .profile del usuario o en el .bash_profile. Si lo que no queremos es que el usuario salga del script con usando la combinacin de teclas Ctrl-C, lo que haremos es capturar la seal y hacer que se ejecute nuevamente el script que se llamar simplemente menu.
trap './menu' 2 while : do echo 'a) Listado de archivos' echo 'b) Da y hora actual' echo 'c) Mes actual' echo 'Seleccione: ' read ELECCION case $ELECCION in a|A) ls;; b|B) date;; c|C) cal;; *) echo "No eligi ninguna opcin valida";; esac done
Como se ve al principio del script se utiliza el comando trap que al captura la seal 2 (SIGINT) que produce el Ctrl-C relanza el script. Al final del script se ve que se llama nuevamente dado que al ejecutarse el comando de cada eleccin se quiere que el men siga funcionando. Practicar con estas construcciones ser de gran ayuda para entender el proceso de construccin de script y los preparara para script ms complejos usando otros interpretes como el sed, awk y el lenguaje perl. Para mayor informacin respecto
a la construccin de script, remitirse a las pginas de manual del intrprete de comandos, en este caso man bash.