Tuberías: lo que necesitas saber para empezar a usarlas en GNU/Linux
Una tubería o pipe es en realidad una canalización disponible para UNIX/Linux y que resulta de lo más práctico. Pero para entender bien lo que es una tubería, debes saber que en un entorno *nix tiene 3 corrientes built-in de datos. Eso, para el que no lo sepa, quiere decir que los datos pueden viajar hacia o desde tres puntos.
Luego entenderás esto de una mejor forma, pero lo que quiero que te quede claro ahora es que con una tubería lo que puedes hacer es canalizar de uno de esos puntos a otros. Eso permite llevar la salida o resultado que arroja un programa hacia la entrada de otro para que ése la use, etc. Intentaré explicarlo con unos ejemplos prácticos que te ayudarán a entenderlo muy bien.
Esos puntos de los que hablaba o streams de datos, son:
- stdin: se corresponde con el 0 y es la entrada estándar. Por lo general, la entrada de datos estándar en un sistema *nix es el teclado. Es decir, lo que tecleas será la información usada. Ella tiene un dispositivo especial asociado que es /dev/stdin.
- stdout: identificado con 1, es la salid estándar. Por lo general se corresponde con el monitor o pantalla de tu equipo, que es donde puedes ver la información. Por ejemplo, cuando ejecutas un comando ls el listado de contenido se mostrará en la pantalla ¿verdad? El dispositivo asociado es /dev/stdout.
- stderr: identificada con 2, es la salida estándar de error, para cuando sucede algún error en algún programa. El dispositivo asociado es /dev/stderr.
Con una tubería puedes hacer que la salida estándar o stdout de un comando pueda pasar directamente a la entrada estándar de otro. Es decir, puedes hacer que un programa alimente a otro. En vez de usar parámetros introducidos por el teclado, con una pipe se le entrega la información generada por el comando previo mediante esta canalización representada con el símbolo |
Con los ejemplos lo entenderás mejor. Imagina que quieres listar el contenido de un directorio, pero que solo te interesa ver los nombres que coincidan con la palabra doc. Entonces podría usar una tubería para canalizar la salida de ls y llevarla a la entrada del filtro grep para decirle que solo muestre los que coincidan con ese patrón:
ls -l | grep doc
Así, en vez de mostrarte todos los nombres, solo te muestra los que realmente te interesan. Igual puedes hacer con el contenido de un archivo. Imagina que solo quieres ver la información de los procesos con nombre firefox y no todos:
ps aux | grep firefox
En vez de mostrar toda la salida del programa ps en pantalla (stdout), lo que hace es canalizarlo hacia la entrada del filtro grep y solo muestra en la salida lo que se corresponde con el patrón firefox en este caso…
Si quieres, puedes usar varias tuberías para llevar la salida de un comando a la entrada de otro segundo comando, y la salida de ese segundo hacia la entrada de un tercero y así sucesivamente. Por ejemplo:
cat libro | grep love | more
Como ves, las posibilidades son muchas, todas las que te imagines y estén permitidas. Incluso mostrar solo las primeras, las últimas líneas de un archivo, contar las líneas que el entran a wc que provienen de listado, e incluso ordenarlas:
cat listado | head cat listado | tail cat listado | wc -l cat listado | sort
También puedes trabajar con los errores con |& y por ejemplo buscar la palabra alerta en la salida de un script si falla:
./miscript |& grep alerta
Y por último, existen dos comandos muy ligados a las tuberías que son tee y xargs y que pueden extender aún más las posibilidades de éstas. En el caso de tee lo que permitirá es mostrar el resultado del programa previo en la salida estándar para que lo puedas ver, y además de eso, lo puede canalizar hacia otro archivo. Un ejemplo sería si listas el contenido de un directorio y quieres ver la salida de ls -l en el momento y también que se guarde en un archivo listado.txt:
ls -l | tee listado.txt
De no usar tee no podrías ver el resultado a la salida en tu consola…
Y xargs es aún más interesante en algunos casos. En este caso es capaz de construir un comando a partir de la entrada estándar que recibe a través de la tubería. Dicho de otro modo, es capaz de captar todo lo que un programa previo ha lanzado por su salida y que llega a xargs a través de la tubería para pasárselo a su vez a otro comando como argumentos.
¿Aún no lo captas? Lo verás mucho mejor con un ejemplo. Imaginate que quieres eliminar todos los malditos archivos thumbs.db de un directorio, disco o partición. Si hay muchos, es posible que sea imposible ir uno a uno con el comando rm para borrarlos manualmente. Pero con xargs se puede automatizar todo. Y lo puedes hacer usando find para localizarlos, enviar la salida a través la entrada de xargs y éste a su vez le irá entregando a rm los nombres como argumentos. Por tanto, se borrarán todos los localizados automáticamente:
find ./ -name "thumbs.db" | xargs rm
Por ejemplo, imagina que find localiza /home/nombre/thumbs.db, /media/prueba/thumbs.db y /tmp/thumbs.db. Pues xargs los va a entregar a rm como si fuesen argumentos. Es decir, como si hubiésemos ejecutado: rm /home/nombre/thumbs.db, luego rm /media/prueba/thumbs.db y después rm /tmp/thumbs.db.