Tubos y Redirecciones (Pipes and Redirection)

Tubos y Redirecciones (Pipes and Redirection)

0 = stdin, 1 = stdout, 2 = stderr

Algunos conceptos.
En linux existen 3 archivos muy importantes y que generalmente pasan desapercibidos. Estos se encuentran en /dev y son:
stdin, stdout y stderr.

STDIN: es el “STandarD INput” o entrada estandar, es el lugar en donde un proceso toma generalmente su entrada, por defecto el teclado. El archivo /dev/stdin es simplemente un archivo que apunta a tu terminal/consola.
Si ejecutas el comando cat sin parámetros podrás ver que toma cualquier caracter desde la entrada estandar (el teclado). Para cortar el proceso usa Control+C

# cat



STDOUT: es el “STandarD OUTput” o salida estandar, es el lugar en donde un proceso generalmente escribe su salida, por defecto, la pantalla. El archivo /dev/stdout es un archivo que apunta, también, a tu terminal/consola.

Un comando ls envía por defecto la salida a la pantalla. Pero si agregamos el caracter de redirección de salida “>” podemos enviarlo a cualquier otro lado.

Por ejemplo, si quisieramos hacer un listado de archivos la carpeta /bin seguramente veríamos pasar por pantalla muy rápidamente toda la lista de archivos y podríamos leer solo la última parte (unas 20 líneas). Esto lo podríamos solucionar enviando la salida estandar a un archivo y luego inspeccionar el archivo más detenidamente, de la siguiente manera:

# ls /bin > misalida.txt



STDERR: es el “STandarD ERRor” o error estandar, es el lugar en donde un proceso generalmente escribe los mensajes de errores, por defecto la pantalla.

Permission denied

Este mensaje es una salida stderr.

Imagínense ejecutar un comando que genera muchas líneas de salida y quizás muchos errores, que seríamos incapaces de leer, dada la velocidad con la que aparecen en nuestra pantalla.
Un ejemplo de esto es cuando usamos el comando tar como un usuario común:

$ tar cvf procs.tar /proc

Este comando generará una larga salida con errores debido a los permisos y a que algunos archivos permanecen abiertos.

Para analizar bien deberíamos redireccionar las salidas para leerlas con más tranquilidad y en detalle:

$ tar cvf procs.tar /proc >detalle.txt 2>errores.txt

Con este comando direccionamos la salida estandar al archivo detalle.txt y los errores estandar al archivo errores.txt.

¿Porqué hay un número 2 antes de > en el comando?

Este número indica la salida: 0 = stdin, 1 = stdout, 2 = stderr. Si no colocara el número 2, los archivos detalle.txt y errores.txt contendrían exactamente la misma información: sólo la salida estandar, ya que los errores nunca se almacenarían.

En “humano” el comando sería: Crear un archivo tar llamado procs.tar, todo el detalle de la salida direccionarlo al archivo detalle.txt y los errores generados enviarlos al archivo errores.txt

Otra buena opción a esta redirección es:

$ tar cvf procs.tar /proc >procs.txt 2>&1

Este comando pone stdout en el archivo procs.txt así como también se envían los errores a &1 que es la salida estandar, o sea que también van a parar al archivo procs.txt.
De esta manera tenemos stdout y stderr en un mismo archivo.

¿> o >>?

Cuando utilizamos un solo símbolo >, estamos indicando que se cree un archivo que contendrá la salida estandar. Si el archivo existe, se sobreescribirá.
Si queremos agregar a ese archivo basta con indicar dos caracteres >> (cuando el archivo destino no exista lo creará).

En una depuración de comandos es bueno realizar el agregado con >>, de lo contrario perderíamos la primer información:

$ tar cvf bins.tar /bin >detalle.txt 2>errores.txt
$ tar cvf procs.tar /procs >>detalle.txt 2>>errores.txt

Al ejecutar ambos comandos, la salida se agregará en detalle.txt y los posibles errores quedarán registrados en errores.txt.

Pipe o tubo.

Se utiliza para unir comandos, donde la salida del primer comando es la entrada del segundo. Se representa por el caracter | .

Uno de los usos más comunes es pausar un listado muy largo para analizar en detalle:

$ cat archivo.txt | more

La salida de cat es la salida estandar (pantalla), pero al utilizar el pipe esa salida la entubamos hacia la entrada del comando more.

Otro ejemplo sería redireccionando varios comandos:

$ ps ax | grep ssh | grep -v grep

Aquí realizamos un ps ax que nos mostraría la lista completa de procesos, al filtrar con grep ssh solo nos mostraría aquellas líneas que contengan la palabra ssh, pero como el mismo comando grep ssh aparece y no nos interesa, volvemos a filtrar con grep quitando las líneas que contengan la palabra grep (grep -v grep).

Un ejemplo muy útil para matar todas las instancias de ssh sería como sigue:

$ for pid in `ps ax | grep sshd | grep -v grep | awk {'print $1'}`; do kill -9 $pid; done

Explicando: realizamos un bucle con for, el cual toma cada línea de lo que está dentro de las comillas ` ` y luego hace un kill -9 de cada resultado.
Fíjense que es igual al ejemplo anterior, solo que hemos agregado el uso de awk para mostrar el primer campo (que es el pid, Process ID).
Si ejecutamos ps ax | grep sshd | grep -v grep | awk {‘print $1′} nos daría una lista de PIDs de cada instancia de sshd. Al estar dentro del bucle for, procesaríamos cada pid con el comando kill.

awk

AWK fue una de las primeras herramientas en aparecer en Unix (en la versión 3) y ganó popularidad como una manera de añadir funcionalidad a las tuberías de Unix.

Para no tener que recordar todo este comando podríamos crear un script y usar variables para pasar la búsqueda de procesos:

$ cat mataprocesos
#!/bin/bash
#$1 es el primer valor que toma de línea de comandos
rm /tmp/mataprocesos.err
PROCESO=$1
if [ -z $PROCESO ]; then
echo "Debe ingresar el nombre de proceso"
echo "Uso:"
echo " mataprocesos "
exit
fi
for NROPID in `ps ax | grep $PROCESO | grep -v grep | awk {'print $1'}`; do
kill -9 $NROPID 2>> /tmp/mataprocesos.err;
done
SIZE=`stat -c %s /tmp/mataprocesos.err`
if [ "$SIZE" -ne 0 ]; then
echo "Errores producidos"
more /tmp/mataprocesos.err
fi

Le damos permisos de ejecución y si queremos le hacemos un link simbólico dentro de /usr/bin para que sea accesible desde cualquier punto.

NOTA: si bien existe el comando pkill (que mata procesos respecto del nombre pasado) me pareció un buen ejercicio para ver las redirecciones.

Comentarios