Módulo 3 — Manejo de archivos de texto mediante línea de comandos
Duración estimada: 4 h
Objetivos
Al finalizar este módulo serás capaz de:
- Ver el contenido de un archivo de texto de varias formas (
cat,less,head,tail). - Contar líneas, palabras y caracteres con
wc. - Extraer columnas de un archivo delimitado con
cut, y combinarlas conpaste. - Ordenar líneas con
sorty eliminar duplicados conuniq. - Transformar texto (mayúsculas/minúsculas, eliminar caracteres) con
tr. - Encadenar estas herramientas para responder preguntas reales sobre un archivo, incluso cuando los datos tienen inconsistencias.
Materiales
Este módulo usa dos archivos de datasets/:
species_observations.csv
sample_id,date,site,latitude,longitude,species,count,notes
S001,2024-05-12,SiteA,40.123,-3.456,Quercus_robur,3,Adultos en borde de camino
S002,2024-05-12,SiteA,40.123,-3.456,Pinus_sylvestris,5,Plantación cercana
S003,2024-06-01,SiteB,41.001,-3.500,Fragaria_vesca,12,Bosque claro
S004,2024-06-02,SiteC,40.900,-3.600,Arabidopsis_thaliana,30,Parcel experimental
S005,2024-06-15,SiteB,41.001,-3.500,Betula_pendula,2,Jóvenes
registro_campo_bruto.csv (ya lo usaste en el módulo de expresiones regulares — es un registro de campo con mayúsculas/minúsculas inconsistentes y espacios sobrantes, tal como llega en la vida real):
sample_id,fecha,localidad,especie,notas
S101,2024-04-02,Sierra de Gredos,Quercus robur,Ejemplar adulto
S102,2024-04-02,sierra de gredos,quercus robur,Cerca del rio
S103,2024-04-03,Sierra De Gredos,QUERCUS ROBUR,Varios individuos jovenes
S104,2024-04-05,El Escorial,Pinus sylvestris,Buen estado
S105,2024-04-05,el escorial,Pinus silvestris,Posible plaga
S106,2024-04-05,El escorial ,Pinus sylvestris,Revisar corteza
S107,2024-04-10,Sierra de Guadarrama,Betula pendula,Hoja amarillenta
S108,2024-04-10,Sierra de guadarrama,betula Pendula,Cerca del arroyo
S109,2024-04-12,Sierra de Gredos,Qurcus robur,Posible error de tipeo
S110,2024-04-15,Picos de Europa,Fagus sylvatica,Bosque denso
S111,2024-04-15,picos de europa,Fagus silvatica,Sotobosque humedo
S112,2024-04-15,Picos De Europa,FAGUS SYLVATICA,Zona protegida
Ver el contenido de un archivo: cat, less, head, tail
cat vuelca el archivo entero en la terminal, de golpe:
~$ cat species_observations.csv
sample_id,date,site,latitude,longitude,species,count,notes
S001,2024-05-12,SiteA,40.123,-3.456,Quercus_robur,3,Adultos en borde de camino
S002,2024-05-12,SiteA,40.123,-3.456,Pinus_sylvestris,5,Plantación cercana
...
Para un archivo de miles de líneas, cat no es práctico: el texto se desplaza fuera de la pantalla antes de que puedas leerlo. less abre el archivo en un visor paginado — puedes bajar con las flechas o Espacio, subir con b, buscar con /palabra, y salir con q — sin cargar nunca todo el archivo en memoria de golpe.
head y tail muestran solo el principio o el final. Por defecto son 10 líneas; con -N eliges cuántas:
~$ head -4 species_observations.csv
sample_id,date,site,latitude,longitude,species,count,notes
S001,2024-05-12,SiteA,40.123,-3.456,Quercus_robur,3,Adultos en borde de camino
S002,2024-05-12,SiteA,40.123,-3.456,Pinus_sylvestris,5,Plantación cercana
S003,2024-06-01,SiteB,41.001,-3.500,Fragaria_vesca,12,Bosque claro
~$ tail -2 species_observations.csv
S004,2024-06-02,SiteC,40.900,-3.600,Arabidopsis_thaliana,30,Parcel experimental
S005,2024-06-15,SiteB,41.001,-3.500,Betula_pendula,2,Jóvenes
head -4 incluye la cabecera (la primera línea del archivo) más las 3 primeras filas de datos — si quieres saltarte la cabecera, dile a tail que empiece en la línea 2 con tail -n +2 (el + significa “desde esta línea hasta el final”, en vez de “las últimas N líneas”).
Contar: wc
wc (word count) cuenta líneas (-l), palabras (-w) o caracteres (-c):
~$ wc -l species_observations.csv
6 species_observations.csv
El archivo tiene 6 líneas: la cabecera más 5 observaciones. Esta es una fuente habitual de errores de “uno de más” (off-by-one): si quieres el número de observaciones, es wc -l menos 1, o directamente cuenta desde la línea 2 con tail -n +2 archivo | wc -l.
Extraer columnas: cut
cut -d',' -f3,6 extrae las columnas 3 y 6 de un archivo separado por comas (-d indica el delimitador, -f los números de columna):
~$ cut -d',' -f3,6 species_observations.csv
site,species
SiteA,Quercus_robur
SiteA,Pinus_sylvestris
SiteB,Fragaria_vesca
SiteC,Arabidopsis_thaliana
SiteB,Betula_pendula
Combinar columnas: paste
paste hace lo contrario de cut: une archivos línea a línea, columna junto a columna. Es útil cuando tienes datos relacionados repartidos en varios archivos:
~$ cut -d',' -f1,3 species_observations.csv > ids_sites.csv
~$ cut -d',' -f6,7 species_observations.csv > especie_count.csv
~$ paste -d',' ids_sites.csv especie_count.csv
sample_id,site,species,count
S001,SiteA,Quercus_robur,3
S002,SiteA,Pinus_sylvestris,5
...
Ordenar: sort
Por defecto sort ordena alfabéticamente. -n ordena numéricamente (imprescindible para números, porque alfabéticamente “10” va antes que “9”), -r invierte el orden, y -t'DELIM' -kN,N ordena por una columna concreta:
~$ tail -n +2 species_observations.csv | sort -t',' -k7,7 -nr
S004,2024-06-02,SiteC,40.900,-3.600,Arabidopsis_thaliana,30,Parcel experimental
S003,2024-06-01,SiteB,41.001,-3.500,Fragaria_vesca,12,Bosque claro
S002,2024-05-12,SiteA,40.123,-3.456,Pinus_sylvestris,5,Plantación cercana
S001,2024-05-12,SiteA,40.123,-3.456,Quercus_robur,3,Adultos en borde de camino
S005,2024-06-15,SiteB,41.001,-3.500,Betula_pendula,2,Jóvenes
-k7,7 dice “ordena por la columna 7 y solo por la 7” (sin el segundo 7, sort seguiría comparando columnas posteriores en caso de empate). -nr combina numérico (-n) y descendente (-r).
Eliminar duplicados: uniq
uniq elimina líneas duplicadas — pero con una condición importante: solo detecta duplicados en líneas consecutivas. Si las líneas iguales no están juntas, uniq no las agrupa. Por eso casi siempre verás sort justo antes de uniq en una tubería: sort agrupa las líneas iguales, y entonces uniq puede eliminarlas. Con -c, además de eliminar duplicados, cuenta cuántas veces aparecía cada línea.
Transformar texto: tr
tr sustituye o elimina caracteres, uno a uno. tr '[:upper:]' '[:lower:]' convierte todo el texto a minúsculas (sustituye cada mayúscula por su minúscula correspondiente):
~$ echo "SIERRA DE GREDOS" | tr '[:upper:]' '[:lower:]'
sierra de gredos
Un problema real: contar localidades correctamente
Quieres saber cuántas localidades distintas hay en registro_campo_bruto.csv y cuántas muestras tiene cada una. La receta obvia es cut + sort + uniq -c:
~$ cut -d',' -f3 registro_campo_bruto.csv | tail -n +2 | sort | uniq -c
1 el escorial
1 El escorial
1 El Escorial
1 picos de europa
1 Picos de Europa
1 Picos De Europa
1 sierra de gredos
2 Sierra de Gredos
1 Sierra De Gredos
1 Sierra de guadarrama
1 Sierra de Guadarrama
11 grupos, cuando en realidad solo hay 4 localidades. El problema es exactamente el mismo que viste en el módulo de expresiones regulares: uniq compara el texto tal cual, y para él Sierra de Gredos y sierra de gredos son líneas distintas. Añadir tr para pasar todo a minúsculas ayuda, pero no del todo:
~$ cut -d',' -f3 registro_campo_bruto.csv | tail -n +2 | tr '[:upper:]' '[:lower:]' | sort | uniq -c
2 el escorial
1 el escorial
3 picos de europa
4 sierra de gredos
2 sierra de guadarrama
Ya solo queda un grupo partido en dos: el escorial y el escorial (con un espacio final, la misma inconsistencia de la fila S106 que corregiste con sed en el módulo anterior). Eliminando ese espacio sobrante antes de ordenar, el resultado es por fin correcto:
~$ cut -d',' -f3 registro_campo_bruto.csv | tail -n +2 | tr '[:upper:]' '[:lower:]' | sed 's/ *$//' | sort | uniq -c
3 el escorial
3 picos de europa
4 sierra de gredos
2 sierra de guadarrama
3 + 3 + 4 + 2 = 12, que coincide con las 12 filas de datos del archivo. Esta secuencia — normalizar mayúsculas, limpiar espacios, y solo entonces ordenar y contar — es el patrón que usarás una y otra vez al analizar datos recogidos a mano.
Ejercicios
- Muestra el contenido completo de
species_observations.csvconcat. - Muestra las 3 primeras filas de datos (sin contar la cabecera) con
head, y las 2 últimas contail. - Cuenta cuántas observaciones (sin contar la cabecera) hay en
species_observations.csv. - Extrae solo las columnas
siteyspeciesdespecies_observations.csvconcut. - Ordena las observaciones de
species_observations.csvpor número de individuos (count) de mayor a menor. - Usando
cut, dividespecies_observations.csven dos archivos: uno consample_idysite, otro conspeciesycount. Vuelve a unirlos conpasteen el orden original. - En
registro_campo_bruto.csv, cuenta cuántas veces aparece cada localidad usandocut,sortyuniq -c, sin ninguna normalización previa. Comprueba que obtienes 11 grupos en vez de 4. - Corrige el resultado del ejercicio anterior añadiendo
tr(minúsculas) ysed(eliminar espacios finales) antes desort/uniq -c. Deberías obtener exactamente 4 localidades, con recuentos que sumen 12.
Soluciones
cat species_observations.csvhead -4 species_observations.csv(incluye la cabecera + 3 filas) ytail -2 species_observations.csvtail -n +2 species_observations.csv | wc -l→5cut -d',' -f3,6 species_observations.csvtail -n +2 species_observations.csv | sort -t',' -k7,7 -nr~$ cut -d',' -f1,3 species_observations.csv > ids_sites.csv ~$ cut -d',' -f6,7 species_observations.csv > especie_count.csv ~$ paste -d',' ids_sites.csv especie_count.csvcut -d',' -f3 registro_campo_bruto.csv | tail -n +2 | sort | uniq -c→ 11 grupos.cut -d',' -f3 registro_campo_bruto.csv | tail -n +2 | tr '[:upper:]' '[:lower:]' | sed 's/ *$//' | sort | uniq -c→ 4 grupos (el escorial: 3,picos de europa: 3,sierra de gredos: 4,sierra de guadarrama: 2).