En bioinformática es muy común tener los datos guardados en un archivo simple de texto plano. Estos archivos toman distintos formatos según el programa que lo genere, por ejemplo fasta, FASTQ, GFF, GTF, SAM, bed, y un largo etc, pero todos ellos son archivos simples de texto plano. Transformar archivos de texto de un formato a otro suele ser una tarea de todos los días en bioinfo.
En este práctico nos vamos a concentrar en el uso de los comandos grep
, sed
, y awk
, y en las posibilidades que nos brindan para el procesamiento de archivos de texto en los típicos formatos de salida que manejan los programas bioinformáticos.
Antes de empezar con el contenido del práctico, descarguen a sus máquinas virtuales los archivos que vamos a utilizar durante el práctico, ubicados en el servidor rnaseq, en /home/estudiantes/archivos_p2
.
usuario@equipo:~$ scp -r estudiantes@rnaseq.fcien.edu.uy:/home/estudiantes/archivos_p2 .
Para aquellos que estén trabajando en rnaseq, copien los archivos a su directorio personal con el siguiente comando:
usuario@equipo:~$ cp -r /home/estudiantes/archivos_p2 .
grep
busca un patrón o una expresión en los archivos de entrada e imprime a la salida estándar las líneas que lo contengan. Comenzando en la primera línea del archivo, grep la compara con la expresión de búsqueda, y si la comparación da resultado positivo imprime la línea. El proceso se repite línea a línea hasta que llega al final del archivo.
El formato del comando es:
usuario@equipo:~$ grep patrón file
o
usuario@equipo:~$ {comando} | grep patrón
Esto devuelve todas las líneas que contienen una cadena de texto que coincide con la expresión patrón en la entrada, sea un archivo o la salida de un comando anterior. Por ahora pensaremos en las expresiones como cadenas de texto, entonces grep
devuelve todas las líneas que contienen patrón
como una subcadena.
Ejemplo:
usuario@equipo:~$ cat ex1.fa #inspeccionamos el contenido del archivo ex1.fa
usuario@equipo:~$ grep ">" ex1.fa #buscamos las líneas que contienen el caracter ">"
>seq1
>seq2
grep
-v
imprime el resultado inverso, es decir las líneas que no coinciden con el patrón-c
imprime el número de líneas que coinciden con la expresión-i
ignora mayúsculas/minúsculas-An
imprime n líneas posteriores a la línea que contiene el patrón buscado-Bn
imprime n líneas anteriores a la línea que contiene el patrón buscado-w
imprime sólo las líneas cuyas coincidencias forman palabras enteras-E
soporte extendido para expresiones regularesEjemplos:
# buscamos las líneas que NO contienen el caracter ">"
usuario@equipo:~$ grep -v ">" ex1.fa
# contamos la cantidad de veces que aparece el carácter ">
usuario@equipo:~$ grep -c ">" ex1.fa
Las expresiones regulares son cadenas de caracteres basadas en reglas sintácticas que permiten definir de manera abstracta patrones de búsqueda. Cada carácter en una expresión regular es o bien un meta-carácter, que tiene un significado especial, o un carácter regular que tiene un significado literal. El meta-carácter por excelencia es el punto .
, que coincide con cualquier carácter. Veamos un ejemplo:
usuario@equipo:~$ grep seq. ex1.fa
>seq1
>seq2
Notar que el “.” coincide tanto con “1” como con “2”.
Cuando trabajamos con expresiones regulares en grep, en general nos va a convenir usar la opción -E, que nos da un soporte extendido para expresiones regulares.
(carácter)?
La expresión coincide con cero o una instancia del carácter.#buscamos las líneas que contienen las secuencias "AAATCC" o "AAACC", es decir que la "T" puede estar o no
usuario@equipo:~$ grep -E AAAT?CC ex1.fa
(carácter)*
La expresión que consiste en un carácter seguido de un asterisco coincide con cualquier número (incluyendo cero) de repeticiones de ese carácter. En particular, la expresión .*
(cualquier carácter, cero o mas veces) coincide con cualquier cadena y, por lo tanto, actúa como un “comodín”.#similar a la anterior, pero ahora puede haber un número indeterminado de "T"s
usuario@equipo:~$ grep -E AAAT*CC ex1.fa
Para hacer coincidir con un carácter de una lista de caracteres, usamos [ ]
. Dentro de los corchetes van todos los caracteres admitidos. Por ejemplo:
#buscamos las líneas que contienen las secuencias "AAATCC" o "AAAGCC"
usuario@equipo:~$ grep -E AAA[TG]CC ex1.f
También se permiten los rangos de caracteres: [0-9]
encuentra cualquier número y [a-zA-Z]
encuentra cualquier letra del alfabeto.
Los paréntesis rectos también pueden ser usados para encontrar no-coincidencias, usando el símbolo ^
como el primer carácter dentro de los paréntesis. Por ejemplo, [^actgACTG]
puede ser usado para encontrar las líneas que contengan caracteres que no sean uno de los cuatro nucleótidos.
Cuando el carácter ^
se encuentra al principio de la expresión simboliza el comienzo de línea; cuando el carácter $
se encuentra al final de la expresión simboliza el final de línea. Estos operadores, conocidos como anclas, son útiles de muchas maneras. Supongamos que queremos encontrar una línea que no sólo contenga nuestra expresión sino que la misma se corresponda con la linea completa, o que se encuentre al comienzo o al final de la línea. Veamos un ejemplo con un archivo en formato FASTQ.
El formato FASTQ es un formato basado en texto para almacenar tanto una secuencia biológica (generalmente una secuencia de nucleótidos) como sus puntajes de calidad correspondientes. El formato usa 4 líneas por secuencia:
+ La línea 1 comienza con un `@` seguido del identificador de la secuencia.
+ La línea 2 tiene la secuencia en sí.
+ La línea 3 comienza con un `+` opcionalmente seguido del mismo identificador de la línea 1.
+ La línea 4 codifica los valores de calidad para la secuencia en la línea 2 y debe contener el mismo número de símbolos que caracteres en la secuencia.
Para contar cuantas secuencias hay en un archivo fastq, busquemos las líneas correspondientes al identificador de la secuencia.
usuario@equipo:~$ head ex2.fastq #examinamos el archivo fastq
usuario@equipo:~$ grep -c ^@SRR ex2.fastq #contamos los encabezados
50
Son caracteres precedidos de una barra invertida. Dicha barra invertida realiza una de las dos siguientes acciones: (a) elimina un significado especial implícito de un carácter, o (b) agrega un significado especial a un carácter “no especial”.
Por ejemplo, si queremos buscar una expresión que contiene espacios, podemos o bien encerrar nuestra expresión entera entre comillas, o “escapar” el espacio, anteponiendo al carácter " " una barra invertida. Ejemplo:
sed
es un editor de flujos de texto que lee y modifica un texto línea a línea de acuerdo a un script. Los comandos de edición de sed permiten entre otras cosas sustituir o borrar. En general, la forma en que usamos sed es la siguiente:
usuario@equipo:~$ sed 'comando_sed' file
usuario@equipo:~$ {comando} | sed 'comando_sed'
Por defecto, el resultado se escribe a la pantalla. Puede redirigir la salida a un nuevo archivo con el operador >
, o si desea editar el archivo existente en su lugar, debe usar la opción -i
. Tener cuidado con esta opción, el resultado es una modificación irreversible.
Las expresiones regulares de sed
son esencialmente las mismas que las de grep
. Los caracteres especiales también son esencialmente los mismos, pero con algunas diferencias clave como la barra /
y el &
, que son caracteres especiales en sed.
En su forma más simple, el formato del comando es sustituir es:
usuario@equipo:~$ sed 's/patrón/texto_nuevo/flag' archivo
No vamos a discutir los distintos flags, por ahora sólo vamos a utilizar el flag g
(por global), que reemplaza todas las coincidencias que encuentra. Veamos un ejemplo sencillo.
Supongamos que queremos cambiar los encabezados de nuestro archivo fasta, cambiando la palabra “seq” por “yeast”. El comando de sed sería:
usuario@equipo:~$ sed 's/seq/yeast/g' ex1.fa > yeast.fa
usuario@equipo:~$ head yeast.fa #examinamos el archivo con los encabezados editados
El ampersand es usado para representar el patrón de búsqueda en el comando sustituir. Cualquiera que sea el texto que coincida con el patrón definido, puede utilizar el ampersand para recuperarlo en el patrón de reemplazo. Ejemplo:
usuario@equipo:~$ sed 's/seq/&_yeast/g' ex1.fa > seq_yeast.fa
usuario@equipo:~$ head seq_yeast.fa #examinamos el archivo con los encabezados editados
En este ejemplo el “&” representa el patrón de búsqueda “seq”, con lo que "&_yeast" se expande a “seq_yeast”.
La sintaxis del comando delete de sed
es muy sencilla: '/patrón/d'
. Por ejemplo:
# eliminamos las líneas que contienen "seq", es decir los encabezados
usuario@equipo:~$ sed '/seq/d' ex1.fa
ex2.fastq
para que pase del formato FASTQ al formato fasta. Sugerencia: combinar los comandos grep
y sed
.Antes de introducir el siguiente comando vamos a ver un formato de salida de blastn
con el que vamos a trabajar durante el resto del curso. blastn
se puede correr localmente (en nuestras máquinas o en el servidor remoto) por línea de comando. La salida puede tener distintos formatos. Uno de los más útiles para trabajar con herramientas de línea de comando como awk es el formato tabular 6, donde cada columna corresponde a un dato del mapeo de blast. Por ejemplo, la columna 1 corresponde al query ID, la columna 2 al subject ID, la 3 al porcentaje de identidad, y la 4 al largo del alineamiento. Puede a qué corresponde el resto de las columnas en http://www.metagenomics.wiki/tools/blast/blastn-output-format-6.
awk a la vez es un lenguaje de scripting para escaneo y procesamiento de patrones de texto, creado por Aho, Weinberger y Kernighan, y es también el programa que interpreta ese lenguaje, al que invocamos con el comando awk
. El programa opera línea por línea en el archivo de entrada y permite el uso de variables, funciones numéricas, operaciones lógicas, edición de texto, etc. Puede ser bastante sofisticado, por lo que esta guía es apenas un comienzo, pero debería darle una idea de lo que awk
puede hacer.
awk
permite escribir scripts en forma de declaraciones que definen condiciones que se deben evaluar en cada línea, y acciones que deben ser ejecutadas cuando la condición evalúa positivamente. Si no hay condiciones, las acciones se ejecutan en todas las líneas. Las condiciones pueden incluir operaciones lógicas, expresiones relacionales o ‘coincidencia de patrones’ (incluyendo expresiones regulares).
awk
Un script awk
tiene una sección opcional BEGIN { }
, en la cual las acciones se ejecutan antes de procesar cualquier contenido del archivo; luego la sección principal con las condiciones a evaluar y acciones a ejecutar en cada línea del archivo, y finalmente hay una sección END { }
, que también es opcional y sus acciones suceden después de que la lectura del archivo haya terminado:
BEGIN {… comandos opcionales de inicialización awk …}
condición {… acción …}
condición {… acción …}
END { … finalización comandos awk …}
El flujo de trabajo de un script de awk
es el siguiente:
De forma general, la forma en que ingresamos un script de awk
por línea de comando es:
usuario@equipo:~$ awk 'condiciones {acciones}' file
o
usuario@equipo:~$ {…comandos…} | awk 'condiciones {acciones}'
awk
considera que cada línea está compuesta por varios campos, cada uno separado por un “separador de campo” (que por defecto es uno o más espacios, o un tabulador). Tomemos como ejemplo la cadena “campo1 campo2 campo3”: awk
ve esta cadena como compuesta por tres campos. Dentro de awk
, el primer campo es referido como $1
, el segundo $2
, etc. Entonces, en nuestro ejemplo, $1
corresponde a la cadena “campo1”.
usuario@equipo:~$ echo "campo1 campo2 campo3" | awk '{print $1}'
campo1
El separador de campos puede ser cambiado mediante la opción -F
. Por ejemplo, si seteamos -F","
el separador va a ser la coma.
usuario@equipo:~$ echo "campo1,campo2,campo3" | awk -F"," '{print $2}'
campo2
$0
Línea actual entera$n
El campo n-ésimo (número n)NF
Número de campos (columnas)NR
Número de registros (líneas)$NF
Último campo (columna)Las condiciones de un script de awk
pueden incluir operaciones lógicas, expresiones relacionales, operaciones aritméticas, o coincidencia de patrones. Para esto se usan una serie de operadores que se describen a continuación:
OPERADORES RELACIONALES
>
Mayor que
<
Menor que
>=
Mayor o igual que
<=
Menor o igual que
==
Igual a
!=
Distinto a
OPERADORES LÓGICOS (BOOLEANOS)
&&
AND
||
OR
!
NOT
OPERADORES ARITMÉTICOS
+
Adición
-
Sustracción
*
Multiplicación
/
División
%
Módulo
BÚSQUEDA DE PATRONES
~
Coincide
!~
No coincide
Ejemplos:
# imprimimos los hits con %ID > 99
usuario@equipo:~$ awk '$3 >= 99 {print $0}' blast.bl
# lo mismo pero agregando la condición de que el largo del alineamiento sea mayor a 10000
usuario@equipo:~$ awk '$3 >= 99 && $4 > 10000 {print $0}' blast.bl
Vamos a obtener el promedio del largo de los alineamientos para aquellos hits cuya identidad es mayor a 99% y el largo del alineamiento es mayor a 10000.
usuario@equipo:~$ awk '$3>99' blast.bl | awk 'BEGIN {sum=0} {sum=sum+$4} END {print sum/NR}'
12861.1
La variable sum
que declaramos en la sección BEGIN
va guardando la suma de los valores del campo 4, que corresponde al largo del alineamientos. Cuando se terminan de procesar las líneas, en la sección END
imprimimos el valor de la suma dividido el número de líneas, que está dado por la variable interna NR
. Esto nos da el promedio.
¿Por qué piensa que hicimos un pipeline con dos comandos awk
en lugar de poner el $3>99
como condición dentro del mismo comando awk
?