← Terminal y Línea de Comandos en Linux Bloque 5 · Redirecciones y tuberías · Tema 24 de 43

Tema 24

Tuberías: conectar comandos

Una barra vertical entre dos comandos. La escribimos desde el primer tema —| less, | wc -l, | head— porque era imposible avanzar sin ella. Es, probablemente, la idea que más distingue a la línea de comandos de cualquier otra forma de usar una computadora: en lugar de buscar un programa que haga lo que necesitas, se arma uno en el momento, enchufando piezas simples. Ahora que conocemos los canales, podemos ver qué hace exactamente esa barra, y aprender a construir con ella.

1. Sin archivos intermedios

Con las redirecciones del tema 23 ya se puede hacer que el resultado de un comando sea procesado por otro. Para contar cuántas cosas hay en un directorio:

terminal: con un archivo intermedio
$ cd ~/practica
$ ls > /tmp/lista.txt               # la salida de ls, a un archivo
$ wc -l < /tmp/lista.txt            # el archivo, a la entrada de wc
4
$ rm /tmp/lista.txt

Funciona, y es incómodo: tres líneas, un nombre que inventar y un archivo que limpiar, para algo que no interesa conservar. El archivo solo sirvió de puente entre la salida de uno y la entrada del otro. La tubería es ese puente, sin el archivo:

terminal: con una tubería
$ ls | wc -l
4

2. El operador |

Una tubería, en inglés pipe, conecta la salida estándar de un comando con la entrada estándar del siguiente. Se escribe con una barra vertical, |, entre los dos.

Una tubería de tres comandos: la salida estándar de cada uno se conecta a la entrada estándar del siguiente; el último escribe en la pantalla. Los mensajes de error de los tres van directamente a la pantalla, sin pasar por la tubería | | 2 2 2 comando 1 produce comando 2 transforma comando 3 transforma Pantalla: los errores de los tres, y la salida del último
Los datos avanzan de izquierda a derecha por el canal 1 de cada comando. El canal 2 de todos sigue conectado a la pantalla.

La línea se lee como una cadena de montaje. Cada comando recibe lo que hizo el anterior, le aplica su transformación y lo entrega al siguiente:

terminal
$ sort tareas.txt | head -n 2
Comprar pan
Estudiar vim

sort ordena las cinco líneas del archivo. En lugar de aparecer en la pantalla, esas cinco líneas entran a head, que deja pasar las dos primeras. Ninguno de los dos comandos sabe que está en una tubería: sort escribe en su salida, como siempre, y head lee de su entrada, como siempre. Es el modelo del tema 22 dando su fruto.

No hay límite para la cantidad de eslabones. Los que están en el medio deben ser filtros: comandos que leen de su entrada y escriben en su salida.

3. Qué ocurre por dentro

Una tubería no ejecuta un comando, espera a que termine y luego ejecuta el otro. Ese sería el método del archivo intermedio. Hace algo más eficiente, y saberlo explica varios comportamientos:

HechoConsecuencia
Todos los comandos arrancan a la vez, como procesos simultáneos.El segundo empieza a trabajar con las primeras líneas, sin esperar las últimas.
Los datos no pasan por el disco. El kernel los guarda en una zona de memoria pequeña, mientras esperan a ser leídos.Se pueden procesar archivos de gigabytes sin ocupar espacio ni memoria adicionales.
Si quien lee es más lento, quien escribe espera. Y al revés.Los procesos se regulan solos; no hay desbordamientos.
Cuando quien lee termina, quien escribe es detenido.Una tubería se corta en cuanto se obtuvo lo necesario.

La última fila se comprueba con un comando hecho para no terminar nunca. yes escribe la letra y, línea tras línea, indefinidamente:

terminal
$ yes | head -n 3
y
y
y
$ 

El indicador volvió enseguida. head leyó tres líneas y terminó; al quedarse sin nadie que leyera, yes fue interrumpido por el sistema. Por eso | head al final de un comando que produce millones de líneas no tarda lo que tardaría el comando completo.

Hay una excepción natural a ese flujo continuo: los comandos que necesitan todos los datos antes de poder responder, como sort, que no puede saber cuál es la primera línea hasta haber visto la última. Esos retienen todo y escriben al final.

4. Construir una tubería paso a paso

Las tuberías largas no se escriben de un tirón. Se construyen de a un eslabón, mirando el resultado de cada paso antes de agregar el siguiente. Veámoslo con una pregunta concreta: ¿qué shells usan las cuentas de este sistema, y cuántas cuentas hay de cada una?

Los datos están en /etc/passwd, cuyo séptimo campo es la shell, como vimos en el tema 16. Usaremos tres filtros que estudiamos a fondo en el tema 26; por ahora alcanza con una línea sobre cada uno:

FiltroQué hace
cut -d: -f7De cada línea, deja solo el séptimo campo, tomando los dos puntos como separador.
sortOrdena las líneas. Con -n, por valor numérico; con -r, al revés.
uniq -cFunde las líneas iguales que están juntas, y antepone cuántas eran.
terminal: primer paso, quedarse con la columna
$ cut -d: -f7 /etc/passwd | head -n 4
/bin/bash
/usr/sbin/nologin
/usr/sbin/nologin
/usr/sbin/nologin
segundo paso: ordenar, para que las iguales queden juntas
$ cut -d: -f7 /etc/passwd | sort | head -n 4
/bin/bash
/bin/bash
/bin/false
/bin/false
tercer paso: contar las repetidas
$ cut -d: -f7 /etc/passwd | sort | uniq -c
      2 /bin/bash
      5 /bin/false
      1 /bin/sync
     38 /usr/sbin/nologin
cuarto paso: ordenar por cantidad, de mayor a menor
$ cut -d: -f7 /etc/passwd | sort | uniq -c | sort -rn
     38 /usr/sbin/nologin
      5 /bin/false
      2 /bin/bash
      1 /bin/sync

Cuatro comandos, ninguno de los cuales sabe nada de usuarios ni de shells, respondieron la pregunta: de las 46 cuentas, solo dos pueden iniciar sesión, root y ana. No existe un programa llamado «contar shells»; no hizo falta.

El método tiene tres reglas. En cada paso se recupera la línea anterior con la flecha arriba y se le agrega un eslabón. Mientras se construye, un | head provisorio al final evita que la pantalla se llene. Y si un paso no da lo esperado, el error está en el último eslabón agregado, porque los anteriores ya fueron vistos funcionando.

5. La filosofía de las herramientas pequeñas

La tubería no es solo un operador. Es la razón por la que los comandos de Unix son como son. Sus creadores, en los Laboratorios Bell, formularon en los años setenta unas pocas reglas de diseño, que se conocen como la filosofía Unix:

PrincipioEn la práctica
Que cada programa haga una sola cosa, y la haga bien.sort ordena. No cuenta, no filtra, no da formato.
Que los programas puedan trabajar juntos.La salida de cualquiera debe poder ser la entrada de otro, aunque nadie haya previsto esa combinación.
Que se comuniquen con texto, porque es la interfaz universal.Líneas de texto simples, sin encabezados ni adornos que estorben al que sigue.

Esto explica rasgos de los comandos que al principio parecían rudeza. Que ls, sin opciones, no muestre un título ni un total. Que wc -l escriba un número a secas. Que nada informe «operación completada». Cada línea de más sería un estorbo para el comando siguiente, que tendría que distinguir los datos de los comentarios. El silencio y la sobriedad de la terminal son requisitos de la composición.

La ganancia es de escala. Con veinte herramientas que hacen una cosa cada una, las combinaciones posibles son miles, y cubren problemas que nadie previó. Un programa grande con veinte funciones resuelve veinte problemas.

La idea ha sido muy imitada, y hoy se la encuentra bajo otros nombres en el diseño de software en general. Su expresión más pura sigue siendo una línea con cuatro comandos y tres barras.

6. Los errores no pasan por la tubería

La tubería conecta el canal 1, y solo ese. Los mensajes de error de cada comando, que viajan por el canal 2, siguen yendo a la pantalla. Es lo que mostraba el diagrama, y lo que comprobamos en el tema 22:

terminal
$ ls notas.txt nada.txt | wc -l
ls: cannot access 'nada.txt': No such file or directory
1

Casi siempre es lo que se quiere: los errores no contaminan los datos, y siguen a la vista. Cuando sí interesa que entren a la tubería —para buscar en ellos, contarlos o paginarlos— se juntan los dos canales antes de la barra, con el operador del tema anterior:

terminal
$ ls notas.txt nada.txt 2>&1 | wc -l
2
Se escribePor la tubería pasaUso típico
cmd1 | cmd2Solo la salida.El normal.
cmd1 2>&1 | cmd2La salida y los errores.Paginar con less un comando que produce muchos errores.
cmd1 |& cmd2Lo mismo; es la abreviatura de Bash.Ídem.
cmd1 2>/dev/null | cmd2Solo la salida; los errores se descartan.Una búsqueda con find en directorios restringidos.

La segunda fila parece contradecir la regla del orden que aprendimos, y no lo hace. La shell prepara primero la tubería, de modo que cuando se procesa 2>&1, el canal 1 ya apunta a ella.

7. Tubería o redirección

Los dos operadores envían la salida de un comando a otro lugar, y es común confundirlos al empezar. La diferencia está en qué hay a la derecha:

comando > xcomando | x
x esUn archivoUn comando
Los datosQuedan guardadosSe procesan y siguen
Puede haber otro eslabón despuésNo: es el finalSí
comando > otro-comando crea un archivo con ese nombre

Escribir ls > wc en lugar de ls | wc no da ningún error: crea en el directorio actual un archivo llamado wc, con el listado dentro. El caso grave es el mismo descuido con una ruta, y con privilegios: una redirección hacia la ruta de un programa del sistema lo reemplaza por texto. A la derecha de > va siempre un archivo.

Los dos se combinan sin problema, y es lo habitual: una tubería que termina en una redirección guarda el resultado final. La redirección de entrada, si la hay, va en el primer eslabón.

terminal
$ cut -d: -f7 /etc/passwd | sort | uniq -c | sort -rn > /tmp/shells.txt

8. tee: guardar y seguir

Una redirección termina la tubería: lo que va al archivo ya no continúa. A veces se quieren las dos cosas, guardar una copia y seguir procesando, o guardar y ver en la pantalla. Para eso existe tee:

tee copia su entrada en dos lugares a la vez: en su salida estándar, y en el archivo que se le indica.

El nombre viene de las piezas de plomería con forma de T, que dividen un caño en dos.

terminal
$ sort tareas.txt | tee /tmp/ordenadas.txt | head -n 2
Comprar pan
Estudiar vim
$ wc -l /tmp/ordenadas.txt
5 /tmp/ordenadas.txt

Por la tubería siguieron las cinco líneas, de las que head mostró dos; y en el archivo quedaron las cinco. tee se intercaló sin alterar lo que pasaba.

UsoComando
Ver la salida y guardarla a la vezcomando | tee resultado.txt
Lo mismo, añadiendo al archivocomando | tee -a registro.txt
Incluir también los errorescomando 2>&1 | tee registro.txt
Guardar un paso intermedio de una tuberíacmd1 | tee paso.txt | cmd2
Escribir en un archivo que requiere privilegioscomando | sudo tee /etc/archivo

El primer uso es el de todos los días: una instalación o una compilación larga, que se quiere seguir en la pantalla y además conservar para revisar si algo falla. Con > no se vería nada mientras ocurre.

El último lo adelantamos en el tema 19, y ahora se entiende del todo. Con sudo comando > /etc/archivo, el archivo lo abre la shell, sin privilegios. Con | sudo tee, lo abre tee, que corre como root. Como tee además repite todo en la pantalla, suele añadirse > /dev/null al final para silenciarlo.

9. xargs: de líneas a argumentos

En el tema 22 vimos que no todos los comandos son filtros. ls, cp, rm, mkdir o chmod no leen su entrada: esperan nombres como argumentos. Ponerlos al final de una tubería no sirve, porque ignoran lo que les llega.

Sin embargo, es una necesidad constante: se tiene una lista de archivos, producida por un comando, y se quiere aplicarles otro. El adaptador entre los dos mundos es xargs:

xargs lee líneas de su entrada estándar y ejecuta un comando poniéndolas como argumentos.

terminal, en ~/practica
$ find . -name "*.txt" | wc -l                 # wc lee la entrada: cuenta los nombres
3
$ find . -name "*.txt" | xargs wc -l           # xargs los pasa como argumentos: cuenta el contenido
    1 ./notas.txt
  361 ./informe.txt
    5 ./tareas.txt
  367 total

La comparación muestra la diferencia entre las dos vías. En la primera línea, wc recibe por su entrada tres líneas de texto y las cuenta: son tres. En la segunda, xargs lee esas tres líneas y ejecuta wc -l ./notas.txt ./informe.txt ./tareas.txt; ahora wc recibe tres nombres de archivo, y cuenta las líneas de cada uno.

… | comando… | xargs comando
Lo que llega se usa comoDatos, por la entradaArgumentos, en la línea de comandos
Sirve conFiltros: sort, grep, wcComandos que actúan sobre archivos: rm, cp, chmod, ls

Para saber qué va a ejecutar, xargs se puede usar con echo delante del comando, la lente que conocemos del tema 9; sin ningún comando, echo es de hecho lo que ejecuta por defecto.

10. xargs en detalle

OpciónEfecto
-n 1Ejecuta el comando una vez por cada elemento, en lugar de una sola vez con todos.
-I {}Reemplaza {} por cada elemento, donde aparezca. Permite ponerlo en el medio de la línea.
-0Espera elementos separados por el carácter nulo, no por espacios ni saltos de línea.
-pMuestra cada comando y pide confirmación antes de ejecutarlo.
-tMuestra cada comando antes de ejecutarlo.
-rNo ejecuta nada si la entrada está vacía.
terminal: ver lo que xargs haría, con echo
$ ls *.txt | xargs echo Archivos:
Archivos: informe.txt notas.txt tareas.txt
$ ls *.txt | xargs -n 1 echo Archivo:
Archivo: informe.txt
Archivo: notas.txt
Archivo: tareas.txt
$ ls *.txt | xargs -I {} echo cp {} /tmp/{}.bak
cp informe.txt /tmp/informe.txt.bak
cp notas.txt /tmp/notas.txt.bak
cp tareas.txt /tmp/tareas.txt.bak

El tercer ejemplo muestra lo que -I resuelve: sin esa opción, los elementos se agregan siempre al final, y un comando como cp, que necesita el destino después, no se podría armar. Quitando el echo, la línea haría las tres copias.

xargs tiene un punto débil, que es el de siempre: los nombres con espacios. Separa los elementos por espacios y por saltos de línea, de modo que mis notas.txt se convierte en dos argumentos. Con un comando que borra, es un accidente.

Con nombres de archivo, find -print0 y xargs -0

La forma segura es que los nombres viajen separados por el carácter nulo, el único que no puede formar parte de un nombre. find los escribe así con -print0, y xargs los lee así con -0: find . -name "*.tmp" -print0 | xargs -0 rm. Ningún espacio, comilla o salto de línea dentro de un nombre puede romper esa tubería. Y antes de un xargs rm, como antes de cualquier borrado, se mira la lista.

Cuando la fuente es find, hay una alternativa que vimos en el tema 10 y que no tiene este problema: -exec comando {} +. Hace lo mismo sin tubería. xargs es necesario cuando la lista viene de otro lado: un archivo, un grep, un ls.

11. El código de salida de una tubería

Cada comando de una tubería termina con su propio código de salida. La tubería entera, sin embargo, informa uno solo:

El código de salida de una tubería es el de su último comando. Los fallos de los anteriores no se reflejan en $?.

terminal
$ ls nada.txt | wc -l
ls: cannot access 'nada.txt': No such file or directory
0
$ echo $?
0

ls falló con código 2, y aun así la tubería «tuvo éxito», porque wc, el último, terminó bien. Para una persona que mira la pantalla no hay problema: el mensaje de error está ahí. Para un script, que decide qué hacer según $?, es una trampa: seguiría adelante con un resultado de cero líneas, como si fuera un dato válido.

Bash da dos remedios:

RecursoQué hace
"${PIPESTATUS[@]}"La lista de los códigos de salida de todos los comandos de la última tubería, en orden.
set -o pipefailHace que la tubería devuelva el código del último comando que haya fallado, y cero solo si todos tuvieron éxito.
terminal
$ ls nada.txt 2>/dev/null | wc -l
0
$ echo "${PIPESTATUS[@]}"
2 0
$ set -o pipefail
$ ls nada.txt 2>/dev/null | wc -l
0
$ echo $?
2
$ set +o pipefail

pipefail es una de las opciones que se activan al comienzo de casi todo script serio, y la reencontrarás en el curso siguiente.

12. Los modismos de todos los días

Algunas terminaciones de tubería se repiten tanto que funcionan como palabras. Varias las venimos usando:

Se agrega al finalPara
| lessLeer con calma una salida larga.
| head, | tailVer solo el comienzo, o el final.
| wc -lSaber cuántos resultados hay.
| grep textoQuedarse con las líneas que contienen algo.
| sortOrdenar.
| sort | uniqEliminar los repetidos.
| sort | uniq -c | sort -rnContar cuántas veces aparece cada valor, del más frecuente al menos.
| tee archivoVer y guardar.
| xargs comandoAplicar un comando a cada resultado.

La séptima fila es el modismo más valioso de toda la línea de comandos, y lo armamos pieza por pieza en la sección 4. Responde a cualquier pregunta de la forma «¿cuál es el más frecuente?»: las direcciones que más visitan un servidor, los errores que más se repiten en un registro, los comandos que más usas. Será el núcleo del proyecto del tema 42.

Ahora se puede leer entera la línea que mostramos en el tema 1 como promesa de lo que la terminal permitía:

¿qué ocupa más espacio en este directorio?
$ du -sh * | sort -rh | head -n 5
EslabónPapelHace
du -sh *FuenteEscribe una línea por cada elemento del directorio, con el espacio que ocupa en formato legible.
sort -rhFiltroOrdena esas líneas por tamaño, entendiendo los sufijos K, M y G, de mayor a menor.
head -n 5FiltroDeja pasar las cinco primeras.

13. Errores y malos hábitos

Se escribeProblemaMejor
cat archivo | grep textoUn proceso de más. cat solo copia el archivo a la tubería.grep texto archivo
sort datos.txt | uniq > datos.txtEl archivo se vacía antes de que sort lo lea: la trampa del tema 23.Un archivo de salida distinto.
ls | rmrm no lee su entrada.ls | xargs rm, o mejor un comodín.
ls > wcCrea un archivo llamado wc.ls | wc
comando | cd directorioCada eslabón corre en un proceso aparte: el cd no afecta a tu shell.No se puede cambiar de directorio desde una tubería.
ls *.txt | xargs comandoFalla con nombres que tienen espacios.comando *.txt, o find … -exec.

La primera fila tiene nombre propio en la cultura de Unix: el «uso inútil de cat». No es un error —el resultado es el mismo— sino un hábito de quien todavía piensa que los filtros necesitan que alguien les «pase» el archivo. Casi todos aceptan el nombre como argumento. Hay un caso en que escribirlo así es defendible: mientras se construye una tubería, tener el archivo al principio y los filtros después hace más fácil ir cambiándolos.

La quinta fila generaliza algo que vimos con sudo cd. Los comandos de una tubería se ejecutan en procesos separados de tu shell, de modo que nada de lo que hagan sobre su propio entorno —cambiar de directorio, definir una variable— persiste cuando la tubería termina.

14. Cuando una tubería no da lo esperado

Una tubería de cinco eslabones que entrega un resultado vacío no dice dónde falló. El método para averiguarlo es el mismo con el que se la construyó, recorrido al revés:

  1. Quitar eslabones desde el final, de a uno, hasta que la salida sea la esperada. El último que se quitó es el culpable. acortar
  2. Mirar la salida de ese punto con | head: ¿tiene la forma que el siguiente filtro supone? mirar
  3. Ver los invisibles con | cat -A: tabulaciones donde se esperaban espacios, o al revés. mirar
  4. Guardar un punto intermedio con | tee /tmp/paso.txt |, para examinarlo aparte. guardar
  5. Revisar los códigos de salida con "${PIPESTATUS[@]}". comprobar

Las causas más frecuentes son tres. Un filtro que selecciona columnas o campos con un separador que no es el real; lo detecta el tercer paso. Un uniq sin un sort antes, que solo funde líneas iguales cuando están juntas. Y un comando del medio que no es un filtro, y deja pasar otra cosa, o nada.

La referencia del tema:

Se escribeQué hace
cmd1 | cmd2La salida de cmd1 es la entrada de cmd2.
cmd1 2>&1 | cmd2, o cmd1 |& cmd2Incluye también los errores.
cmd | tee archivoMuestra la salida y la guarda.
cmd | tee -a archivoLo mismo, añadiendo.
cmd | xargs otroEjecuta otro con las líneas como argumentos.
find … -print0 | xargs -0 otroLo mismo, a salvo de nombres con espacios.
"${PIPESTATUS[@]}"Los códigos de salida de cada eslabón.
set -o pipefailLa tubería falla si falla cualquiera de sus comandos.

Las tuberías conectan los datos de un comando con otro. Queda una forma más de combinar: hacer que la ejecución de un comando dependa del resultado de otro, o que su salida se convierta en parte de otra línea. Es el tema 25, que cierra el bloque.

15. Resumen

16. Preguntas de repaso

Intenta responder cada una antes de abrir la respuesta.

1. ¿Qué conecta exactamente una tubería?

La salida estándar, el canal 1, del comando de la izquierda con la entrada estándar, el canal 0, del comando de la derecha.

2. ¿Qué ventaja tiene ls | wc -l sobre guardar el listado en un archivo y contarlo después?

No hay archivo que nombrar ni que borrar, los datos no pasan por el disco, y los dos comandos trabajan a la vez.

3. yes nunca termina, pero yes | head -n 3 sí. ¿Por qué?

Porque head termina después de leer tres líneas, y cuando el lector de una tubería termina, el sistema detiene al que escribe.

4. ¿Qué condición deben cumplir los comandos que están en el medio de una tubería?

Deben ser filtros: leer de su entrada estándar y escribir en su salida estándar.

5. Enuncia los tres principios de la filosofía Unix.

Que cada programa haga una sola cosa y la haga bien; que los programas puedan trabajar juntos; y que se comuniquen mediante texto.

6. En find / -name "*.log" | wc -l, ¿se cuentan los mensajes «Permission denied»?

No. Viajan por el canal de errores, que no pasa por la tubería: aparecen en la pantalla.

7. ¿Cómo se hace para que los errores también entren a la tubería?

Juntando los canales antes de la barra: comando 2>&1 | otro, o con la abreviatura comando |& otro.

8. ¿Qué diferencia hay entre ls > sort y ls | sort?

La primera crea un archivo llamado sort con el listado. La segunda envía el listado al comando sort.

9. ¿Qué hace tee?

Copia lo que recibe por su entrada a dos destinos: su salida estándar y un archivo.

10. ¿Por qué echo "x" | sudo tee /etc/archivo funciona y sudo echo "x" > /etc/archivo no?

En la segunda, el archivo lo abre la shell del usuario, sin privilegios. En la primera lo abre tee, que se ejecuta como root.

11. ¿Qué diferencia hay entre find . -name "*.txt" | wc -l y find . -name "*.txt" | xargs wc -l?

La primera cuenta cuántos nombres encontró find. La segunda pasa esos nombres como argumentos a wc, que cuenta las líneas de cada archivo.

12. ¿Para qué sirve la opción -I {} de xargs?

Para indicar en qué lugar de la línea se coloca cada elemento, cuando no debe ir al final; por ejemplo, como origen de un cp.

13. ¿Por qué se usa find -print0 | xargs -0?

Porque separa los nombres con el carácter nulo, que no puede aparecer en un nombre de archivo. Así, los nombres con espacios o saltos de línea no se parten en varios argumentos.

14. Un comando falla en medio de una tubería y $? vale 0. ¿Por qué, y cómo se detecta el fallo?

Porque el código de salida de una tubería es el del último comando. Se detecta con "${PIPESTATUS[@]}", o activando set -o pipefail.

15. ¿Qué hace | sort | uniq -c | sort -rn, y por qué hace falta el primer sort?

Cuenta cuántas veces aparece cada línea y las ordena de la más frecuente a la menos. El primer sort es necesario porque uniq solo funde líneas iguales que están contiguas.

Para practicar

  1. Averigua con una tubería cuántos programas hay en /usr/bin, cuántas páginas hay en la sección 1 del manual y cuántos usuarios hay en el sistema.
  2. Reconstruye paso a paso la tubería de la sección 4. Luego adáptala para contar cuántos usuarios tienen cada grupo primario: el cuarto campo de /etc/passwd.
  3. Muestra las tres líneas más largas de tareas.txt en orden alfabético inverso, y la línea 100 de informe.txt, usando solo sort, head y tail.
  4. Ejecuta ls /root | wc -l y ls /root 2>&1 | wc -l. Explica los dos números.
  5. Ejecuta ls -l /etc | tee /tmp/etc.txt | wc -l y compara con wc -l /tmp/etc.txt.
  6. Con find y xargs, obtén el listado largo de todos los archivos .conf que están directamente en /etc, ordenados por tamaño.
  7. Antepone echo para ver qué haría ls *.txt | xargs -I {} mv {} {}.viejo, sin ejecutarlo.
  8. En /tmp, crea un archivo llamado dos palabras.txt. Compara find /tmp -name "*.txt" | xargs ls -l con la versión que usa -print0 y -0.
  9. Ejecuta cat nada.txt | sort | head y mira $? y "${PIPESTATUS[@]}". Repite con set -o pipefail.
  10. Usa history y los filtros de la sección 4 para ver cuántos comandos distintos escribiste. Pista: history | cut -c 8- quita los números de línea.