Comandes de filtre de fitxers (cut, sort, grep, sed, awk...) i de cerca de directoris i fitxers (find, locate, ls) a Linux, expressions regulars, aplicats al bigdata i la bioinformàtica.

Introducció

La forma més ràpida i eficient de llegir i tractar fitxers de text i cercar informació dins dels discos i unitats del nostre sistema operatiu és precisament usant el terminal que ens proporciona. Molt més que utilitzar l'entorn gràfic o usar altres llenguatges de programació que també ho poden fer, però amb un rendiment inferior degut a la càrrega de llibreries.

Per això val la pena aprendre i dominar les comandes de filtre de fitxers (cut, sort, grep, sed, awk...) i de cerca de directoris i fitxers (find, locate, ls) que proporciona Linux, ja que són eines molt potents pel processament de grans volums de dades relacionades amb la bioinformàtica.

Per exemple, si volem filtrar 6 de les 30 columnes i 300 dels possibles 150.000 registres que necessitem d'un fitxer de dades d'enfermetats o de gens amb poques línies de codi és una meravella usar la shell de Linux. Comandes com el grep, el cut o el sed fan meravelles.

El rendiment de realitzar aquest preprocessament i filtratge abans d'utilitzar aquest fitxer per un programari en Pyhton que visualitzi les dades o com a dades d'entrenament per a la nostra futura IA és molt superior que volcar directament el fitxer en un programa fet amb un llenguatge d'alt nivell (Python, PHP, Java, JavaScript).

Preparació entorn i repàs comandes.

En aquesta activitat repassarem algunes comandes i en veurem d'altres de noves, i la millor manera és aplicant-les primerament en un fitxer senzill.

Entra a la teva màquina, crea una carpeta separada i un arxiu de nom "empleades.csv" que contingui les següents dades:

Nom;Cognom;Ciutat;Telèfon;Edat;Email
Cristina;Ouviña;Valencia;96123456;30;ouvina@esfuerzo.com
Silvia;Domínguez;Salamanca;923294400;34;sdom@perfumerias.es
Alba;Torrens;Ekaterinburgo;0073436898812;31;a.torrens@mvp.es
Laia;Palau;Girona;972414114;41;laia@mestitolsqueanys.com
Marta;Xargay;Barcelona;0034904221336;25;marta@hotmail.com
Tamara;Abalde;Vitoria;945139291;32;mihermano@tambienjuega.es
Aitana;Bonmati;Barcelona;003469482919;24;aitanabonmati@fcb.cat
Queralt;Casas;Valencia;00346758410;28;queralt@cultura.es
Maria;Conde Valencia;Kraków;0048531601710;22;conde@wisla.pl
Nogaye;LoSylla;LaSeu;976379156;24;nogaye-losylla@feb.com
Aida;Riko;Fujimaki;0000000000;32;seirin@manga.com
Uliana;Semiónova;Getafe;918765432;39;tachenko@ijosomdelamateixaepoca.es
Alexia;Putellas;Barcelona;0034654848419;28;alexiap@fcb.cat
Claudia;Masip;Tarragona;0034652736471;18;claudia.masip@nastic.com
Nora;Chaib;LHospitalet;003465736471;21;norachaib@uecornella.cat
Sandra;Vericat;LHospitalet;00345574361;33;sandrav2udbellvitge.cat
Jennifer;Hermoso;Barcelona;003495431336;27;jennihermoso@fcb.es
Danae;Boronat;Barcelona;0000000000;41;danae.boronat@fcb.cat
mkdir m01-a041-empleades
cd m01-a041-empleades
nano empleades.csv

Copia i enganxa les dades i guarda-les (Ctrl+X, Y)

Fixa't que el format csv és molt ventatjós pels món científic, ja que permet obrir el fitxer tant en un editor de text pla com gedit o notepad++, com en Libre Office Calc, per a crear els nostres gràfics i taules dinàmiques si volem.

Ara, repassa i prova les comandes que et posem d'exemple per verificar el funcionament i per repassar-les, ja que les hem vist prèviament.

Repàs de comandes bàsiques.

cat → mostra per pantalla un fitxer sense llegir-lo

operador > → et permet guardar la sortida de comandes en un fitxer.

operador | → anomenat pipe o filtre, concatena el text de la sortida d'una comanda.

head, tail → mostren les primeres / últimes línies

wc -l → compta les línies d'un text ( també es poden comptar amb -w -c)

I què podem fer amb aquestes ?

Mostrar les 10 primeres empleades per pantalla, i la capçalera.

head -11 empleades.csv 

Mostrar les 10 últimes empleades i guardar-les en un fitxer separat.

tail -11 empleades.csv > 10ultempleades.csv

Comptar quantes empleades hi ha al fitxer.

cat empleades.csv | wc -l

Volem mostrar les 5 primeres empleades, però sense que es vegi la capçalera.

cat empleades.csv | head -n 6 | tail -n+2 

Filtre de fileres amb grep.

El filtre grep (Global Regular Expression Print) és un dels més apreciats de la Shell, et permet filtrar si un (o més fitxers) contenen una paraula concreta (o no) de forma molt ràpida. L'únic requisit és que sigui informació textual.

Veiem exemples amb el nostre fitxer empleades.csv.

Per exemple, mostra les empleades de Barcelona:

grep Barcelona empleades.csv

Marta;Xargay;Barcelona;0034904221336;25;marta@hotmail.com Aitana;Bonmati;Barcelona;003469482919;24;aitanabonmati@fcb.cat Alexia;Putellas;Barcelona;0034654848419;28;alexiap@fcb.cat Jennifer;Hermoso;Barcelona;003495431336;27;jennihermoso@fcb.es Danae;Boronat;Barcelona;0000000000;41;danae.boronat@fcb.cat

Grep té opcions per fer-lo més flexible, com -c, -n i -v

Mostra les empleades que no són de Barcelona (això es fa amb -v, invert )

grep -v Barcelona empleades.csv

Mostra el númer d'empleades que són de Barcelona (sixò es fa amb -c, és equivalent a fer | wc -l)

grep -c Barcelona empleades.csv

5

També és interessant l'ús de la opció -n que retorna el número de posició dins del fitxer de les linies trobades.

Si vols filtrar per fileres que compleixin 2 valors (almenys un dels 2) ho podem fer així:

grep -E 'Hospitalet|Barcelona' empleades.csv 

Per a realitzar filtres més avançats necessitarem expressions regulars (pròximament)

Filtre i ordenació de columnes: cut, sort

Si només ens interessen unes columnes d'un fitxer (separat per comes o altres paràmetres) podem usar la comanda cut.

Per exemple, si només ens interessen el nom i el correu del fitxer de empleades.txt; aplicariem la comanda cut d'aquesta manera:

cat empleades.csv | cut -d ";" -f 1,2 

Els paràmetres més importants que tenim d'aquesta comanda són:

-d és per indicar el separador. -d ";" en el nostre cas. Per defecte és \t. -f identificador de les columnes que volem, separades per comes. Comença comptant per 1. En el nostre fitxer el nom és la columna 1, el cognom la 2 i el email la última que és el 6.

1       2       3       4            5      6
Marta;Xargay;Barcelona;0034904221336;25;marta@hotmail.com

Podem aplicar alhora comandes com el grep i el sed per obtenir resultats precisos ràpidament.

Mostra el cognom i l'edat de totes les empleades i guarda-les en un fitxer

cat empleades.csv | grep -v Barcelona | cut -d ";" -f 1,2,5 

Ordenació de columnes, sort

La comanda sort agafa la sortida del terminal i la ordena mitjançant diversos criteris.

Per defecte, ordena per la primera columna de la sortida del terminal de forma alfanumèrica

Mostra el nom, cognom i l'edat de les empleades que no són de Barcelona.

cat empleades.csv | grep -v Barcelona | cut -d ";" -f 1,2,5 

Ara, mostra el cognom i edat de les totes empleades, ordenades alfabèticament per congom, i guarda el resultats dins el fitxer consulta_empleades.txt

cut -d ";" -f2,5 empleades.csv | sort > consulta_empleades.txt

Si en comptes d'ordenar per cognom volem ordenar numèricament per edat, ho fem amb dues comandes i un fitxer intermig (empleades_cognom_edat.txt), ja que és més entenedor.

cut -d ";" -f2,5 empleades.csv > empleades_cognom_edat.txt 
sort -t ';' -k2,2n empleades_cognom_edat.txt > informe_empleades.txt

A la primera comanda hem filtrat el fitxer per a què només tingui cognom i edat, abans d'ordenar-lo.

1       2
Xargay;25;

I llavors, el sort ens permet aquestes opcions:

-t és per indicar el separador. -d ";" en el nostre cas. Per defecte és \t. -k identificador de la columnes que volem ordenar, separades per comes. -n serveix per dir-li que volem ordenar la columna numèricament, ja que és un número; sinó ens la ordenaria malament. Per defecte ordena com si fos una cadena de caràcters.

Comandes de reemplaçament de contingut: sed, tr

sed (stream editor) reemplaça una cadena de caràcters indicada per l'usuari per un altre, dins d'una cadena de text més llarga.

En resum, el grep fa el mateix que el Ctrl+F i el sed fa com el Ctrl+H de les aplicacions ofimàtiques, totalment automatitzat.

Anem a estudiar un exemple del sed. Imaginem-nos que tenim aquesta web. Hi apareix 3 vegades la paraula Departament i volem canviar-lo pel nostre nom.

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Web del Departament</title>
</head>
<body>
	<h2>Web del Departament</h2>
	<p><a href="https://chiquitoipsum.com/">Lorem fistrum</a> pecador hasta luego Lucas hasta luego Lucas torpedo fistro condemor. Al ataquerl sexuarl se calle ustée fistro diodeno tiene musho peligro ahorarr a gramenawer papaar papaar caballo blanco caballo negroorl no te digo trigo por no llamarte Rodrigor.</p>
	<h3>Made with Love by Departament, CC-BY-SA 4.0</h3>
</body>
</html>

Ho reemplaçem molt ràpidament amb el sed:

$ sed -i 's/Departament/Miquel/g' web_miquel.html

La sintaxi bàsica de sed és la següent:

Comentem algunes opcions del sed (n'hi ha més):

/g g de global. Ho posem si en comptes de la primera ocurrència volem canviar-les totes. > fitxer_nou per tal de crear una còpia i no perdre la informació anterior

Anem a verificar que ha funcionat; que ara apareix la paraula Miquel allà on apareixia Departament.

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Web del Miquel</title>
</head>
<body>
	<h2>Web del Miquel</h2>
	<p><a href="https://chiquitoipsum.com/">Lorem fistrum</a> pecador hasta luego Lucas hasta luego Lucas torpedo fistro condemor. Al ataquerl sexuarl se calle ustée fistro diodeno tiene musho peligro ahorarr a gramenawer papaar papaar caballo blanco caballo negroorl no te digo trigo por no llamarte Rodrigor.</p>
	<h3>Made with Love by Miquel, CC-BY-SA 4.0</h3>
</body>
</html>

Un altre exemple, sobre el fitxer empleades.csv; eliminar els espais en blanc si n'hi ha:

sed -i 's/ //g' empleats.csv > empleats2.csv

tr reemplaça les aparicions d'un caràcter per un altre que indiqui l'usuari, dins d'una cadena de text.

Molt útil per convertir de majúscules a minúscules (o al revés):

tr '[:upper:]' '[:lower:]' < empleades.csv > empleades_minuscules.csv

O eliminar espais repetits per a què només hi hagi un.

tr -s ' ' < empleades.csv > empleades_sense_espais.csv

Cas pràctic 1. Fitxer enfermentats EEUU Tycho.

Quan el tamany de les dades és molt gran (més d'1MB) pots er útil realitzar el filtratge amb les funcions del sistema operatiu abans de portar-les en una base de dades o en un llenguatge de programació com Python o Java, especialment si comptem amb el llenguatge bash, present al terminal de Linux.

En aquesta secció repassarem com podem utilitzar els mètodes de bash més comuns amb el voluminós dataset d'exemple del Projecte Tycho

Aquest dataset conté un historial del recompte de casos de diverses enfermetats que han afectat als EEUU des del 1888 al 2014.

En alguns anys hi ha molts registres (1900-1950) i d’altres menys, però en total podem tenir més d’10M d’observacions; cadascuna de les quals té 10 columnes d'interès.

Per accedir-hi ens podem registrar (és gratuït) però no ens cal, ja que tenim les dades de fa 2 anys i no ens cal que siguin actualitzades per aquest exemple.

Hem penjat un subset de 1M de línies en aquest fitxer (120 MB un cop descomprimit):

Versió reduïda Tycho

Un cop descarregat, obriu un terminal de Linux i proveu aquestes operacions.

⚠ No obriu el fitxer dirèctament o us arrisqueu a que la màquina se us pengi, o perdreu temps esperant la càrrega ⚠

Mostra les 10 primeres línies del fitxer (la capçalera i 9 més)

cat tycho.csv 

⚠ Mostra tot el contingut del fitxer pel terminal. Si executeu la comanda per accident i no voleu esperar, premeu Ctrl+C per finalitzar el procés. ⚠

cat tycho.csv 

Compta el número de línies en total.

cat tycho.csv | wc -l 

Mostra les 10 primeres línies que continguin el text 1888. En el nostre cas l'any 1888.

head tycho-mini.csv | grep 1888

Fixeu-vos que amb el tros de comanda | grep 1888 podem filtrar per files, de tot el fitxer només les línies que continguin el número 1888. No és perfecte, però segur que seleccionarà totes les mostres de l'any 1888 (i potser algún altre any amb 1888 casos, però això es pot perfeccinar més endavant amb altres comandes o amb Python)

Com podeu veure, tots els filtres que apliquem es mostren per pantalla, però si volem que es guardin en un fitxer disposem de l'operador de redirecció >.

Amb aquesta comanda, guardo la info del fixer de 3 anys en el fitxer anomenat tycho-optim.csv:

cat tycho-mini.csv | grep -E ‘1910|1911|1912> tycho-optim.csv

Amb una sola comanda hem aconseguit reduïr el fitxer a les 78000 línies (aproximadament) que ens interessen. Oi que val la pena aquest preprocessament ?

Per fer els següents exercicis, podeu descarregar el Tycho:

wget https://gitlab.com/xtec/bio/pandas/-/raw/main/data/tycho/tycho78k.csv

Fixa't amb les columnes que disposem originalment dins fitxer CSV de Tycho:

head -n 2 tycho78k.csv
epi_week,country,state,loc,loc_type,disease,event,number,from_date,to_date,url
188824,US,PA,PHILADELPHIA,CITY,TYPHOID FEVER [ENTERIC FEVER],DEATHS,14,1888-06-10,1888-06-16,http://www.ncbi.nlm.nih.gov/pmc/articles/PMC2084171

epi_week Setmana epidemiològica (de l'1 al 52 normalment, algún cop hi ha 53). És una mètrica necessària i molt habitual en la informàtica mèdica.

country País. En aquest dataset només hi ha mostres dels Estats Units, per tant podrem ometre-la. US

state Sigles de l'estat dels EEUU.

loc Nom complet de l'estat dels EEUU. Guardar state i loc (info redundant) només si volem visualitzar mapes.

loc_type En el dataset pot ser CITY o STATE.

disease Enfermetat. Entre [] ens indica informació addicional, que potser en el nostre estudi és necessària i ometre-la ens pot estalviar memòria del dataFrame.

event Cada event pot ser de 2 tipus, i és important distingir-los segons el que volguem estudiar: CASES (número de casos), DEATHS(número de morts causats per la enfermetat). Si volem treballar bé aquest estudi es pot calcular una ràtio de CASES i DEATHS, que el seu resultat serà entre 0 i 1 (1 si tots els casos han estat mortals)

number Important! Número de casos (si event='CASES') o número de morts (si event='DEATHS')

from_date,to_date Dates d'inici i de fi en què es mesura el número de casos. Són (o haurien de ser) intèrvals d'una setmana.

url El projecte Tycho ha escanejat i/o digitalitzat documents de paper a PDF (anys 1980 i anteriors) que demostren els registres realitzats i han de ser molt interessants. Desgraciadament l'enllaç proporcionat no funciona.

Finalment, remarcar que podem observar que el dataset està en format Tidy, que és el que desitgem per poder realitzar estadítica i gràfics. Aquest punt és fonamental verificar-lo abans de començar a investigar un dataset.

  • Cada fila és una observació
  • Cada columna és una variable
  • Cada valor té una única dada

Si el dataset no fos Tidy, hauriem de preprocessar-lo i arreglar-lo fins que ho sigui.

Ara que les coneixem, podem crear una còpia del fitxer que només contingui les columnes de: state,disease,from_date,number. Hem de mirar en quin número de columna estan.

        ,        ,3,        ,       ,6,     ,   ,8      ,9,     ,       , 
epi_week,country,state,loc,loc_type,disease,event,number,from_date,to_date,url

La comanda és:

cat tycho78k.csv | cut -d ',' -f 3,6,8,9 > tycho78k_cropped.csv

I el resultat:

Exercicis. A partir del fitxer tycho78k.csv que has descarregat abans. Columnes:epi_week,country,state,loc,loc_type,disease,event,number,from_date,to_date,url Q1-Compta el número de files que hi ha l'any 1909. Q2-Mostra l'epi_week, event i el number del fitxer: l'any 1910, a l'estat de CHICAGO Q3-Mostra tota la informació els casos mortals de TUBERCULOSIS, (columna event='DEATHS') l'any 1910 a l'estat de CHICAGO. Q4-Guarda en un nou fitxer l'epi_week, state i number del fitxer: de casos de tos ferina (WHOOPING COUGH), (columna event='CASES') l'any 1911. Q5-Elimina el valor CITY de la columna state (per exemple que en comptes de KANSAS CITY només aparegui KANSAS). Q6-Crea un nou fitxer en format tsv: el mateix, que en comptes de ser separat per comes ho sigui per tabuladors.

Q1. Compta el número de files que hi ha l'any 1909.

grep '1909' tycho78k.csv | wc -l

Explicació:

  • grep '1909': Busca totes les línies que contenen l'any 1909 a qualsevol part.
  • wc -l: Compta el nombre de línies.

Q2. Mostra l'epi_week, event i el number del fitxer: l'any 1910, a l'estat de CHICAGO.

grep '1910' tycho78k.csv | grep 'CHICAGO' | cut -d ',' -f1,7,8

Explicació:

  • grep '1910': Filtra les línies que contenen l'any 1910.
  • grep 'CHICAGO': Filtra les línies que contenen l'estat de CHICAGO.
  • cut -d ',' -f1,7,8: Selecciona les columnes epi_week (1), event (7) i number (8).

Q3. Mostra tota la informació dels casos mortals de TUBERCULOSIS, (columna event='DEATHS') l'any 1910 a l'estat de CHICAGO.

grep '1910' tycho78k.csv | grep 'CHICAGO' | grep 'TUBERCULOSIS' | grep 'DEATHS'

Explicació:

  • grep '1910': Filtra l'any 1910.
  • grep 'CHICAGO': Filtra l'estat de CHICAGO.
  • grep 'TUBERCULOSIS': Filtra els casos de tuberculosis.
  • grep 'DEATHS': Filtra els casos mortals (event='DEATHS').

Q4. Guarda en un nou fitxer l'epi_week, state i number del fitxer: de casos de tos ferina (WHOOPING COUGH), (columna event='CASES') l'any 1911.

Filtra els casos de tos ferina (WHOOPING COUGH) de l'any 1911, i després guarda les columnes seleccionades:

grep '1911' tycho78k.csv | grep 'WHOOPING COUGH' | grep 'CASES' | cut -d ',' -f1,3,8 > whooping_cough_1911.csv

Explicació:

  • grep '1911': Filtra l'any 1911.
  • grep 'WHOOPING COUGH': Filtra els casos de tos ferina.
  • grep 'CASES': Filtra els casos (event='CASES').
  • cut -d ',' -f1,3,8: Selecciona les columnes epi_week (1), state (3), i number (8).
  • > whooping_cough_1911.csv: Guarda el resultat en un nou fitxer.

Q5. Elimina el valor CITY de la columna state (per exemple que en comptes de KANSAS CITY només aparegui KANSAS) usa el sed.

Utilitza sed per eliminar la paraula CITY de la columna state:

sed 's/ CITY//g' tycho78k.csv > tycho78k_no_city.csv

Explicació:

  • s/ CITY//g: Substitueix CITY (amb un espai abans) per res (elimina-ho) en tot el fitxer.
  • > tycho78k_no_city.csv: Guarda el fitxer modificat.

Q6. Crea un nou fitxer en format tsv: el mateix, que en comptes de ser separat per comes ho sigui per tabuladors. (usa tr)

Utilitza tr per substituir les comes per tabuladors:

tr ',' '\t' < tycho78k.csv > tycho78k.tsv

Explicació:

  • tr ',' '\t': Substitueix totes les comes per tabuladors.
  • < tycho78k.csv: Indica que tycho78k.csv és el fitxer d'entrada.
  • > tycho78k.tsv: Guarda el resultat en un fitxer tycho78k.tsv en format TSV.

Amb aquests exemples, pots aplicar diferents filtres i transformacions al teu fitxer tycho78k.csv utilitzant comandes senzilles de Linux!

Cas pràctic 2. Genòmica.


Referències.

Per a un pròxim article.

## Ús d'expressions regulars bàsiques.

## Comandes de cerca: find

## Comandes de cerca: grep

## Ús d'expressions regulars avançat.

## Ús del awk

Bash, opendata https://docs.google.com/document/d/1P-B8miHGXWROY9wcDdckaboSXShCzq1GveMh4JKmobs/edit

Regexp: https://docs.google.com/document/d/1SfcI8_y_vvP_TSmpKD83SwKuGpQhMvsN/edit#heading=h.mj87o0m3gmjb

Bash find: https://docs.google.com/document/d/1o065V-yailPPNGFfnRXH_iExwEsGGWlz/edit#heading=h.mj87o0m3gmjb