1. Introducción a los entornos de trabajo UNIX

1.15. Diseño de protocolos automáticos en el terminal

En este apartado os vais a introducir en el diseño de protocolos automáticos en un terminal bash. Dentro del campo de la bioinformática aprender a diseñar protocolos es útil por varias razones. En primer lugar, permite la automatización de tareas repetitivas, lo que ahorra tiempo y reduce el riesgo de errores. En segundo lugar, permite la creación de flujos de trabajo reproducibles, que son esenciales para la investigación científica. En tercer lugar, bash es una herramienta poderosa y flexible que se puede utilizar para manipular conjuntos de datos grandes y realizar análisis complejos. Finalmente, el uso de protocolos (en inglés, script) bash facilita la colaboración y el intercambio de protocolos, lo que hace que sea más fácil para los investigadores reproducir el trabajo de otros y construir sobre él. En general, el diseño de protocolos automáticos en un terminal bash es una forma eficiente y efectiva de realizar análisis de bioinformática.

Al diseñar un protocolo en un terminal bash, hay varios aspectos técnicos y parámetros que deben tenerse en cuenta. Aquí se presentan los aspectos más importantes que hay que considerar.

  • Sintaxis y gramática: el protocolo debe tener una sintaxis y una gramática bien definidas que sean fáciles de entender y seguir.
  • Manejo de errores: el protocolo debe estar diseñado para manejar errores y excepciones de manera elegante. Esto incluye la definición de códigos de error y mensajes.
  • Seguridad: el protocolo debe estar diseñado para garantizar la privacidad y seguridad de los datos. Esto incluye medidas como la encriptación, la autenticación y el control de acceso.
  • Compatibilidad: el protocolo debe ser compatible con el hardware y el software del sistema en el que se utilizará.
  • Eficiencia: el protocolo debe estar diseñado para ser eficiente y optimizar el uso de los recursos del sistema, como la CPU y la memoria.
  • Escalabilidad: el protocolo debe estar diseñado para ser escalable, de modo que pueda manejar cantidades crecientes de datos y usuarios sin degradación del rendimiento.
  • Documentación: el protocolo debe estar bien documentado, con instrucciones claras y ejemplos para su implementación y uso.
  • Pruebas: el protocolo debe ser probado exhaustivamente para asegurar que su funcionalidad y rendimiento cumplan con los requisitos.

Teniendo en cuenta estos aspectos técnicos y parámetros, el protocolo puede ser diseñado para ser efectivo, seguro y eficiente en su funcionamiento. En este apartado se os muestra cómo diseñar protocolos sencillos, y no se tendrá en cuenta todo lo mencionado anteriormente, pero siempre se debe trabajar teniendo en cuenta todas las consideraciones mencionadas.

En este ejercicio se os va a mostrar cómo generar un protocolo para obtener información biológica relevante a partir de 3 secuencias FASTA. Te animo a que realices todos los pasos que se muestran a continuación. Abre un terminal y empieza.

1) Crea un directorio:

$ mkdir fasta_sequence
$ cd fasta_sequence

2) Descarga, en el anterior directorio, y desde la base de datos ENA (European Nucleotide Archive) las secuencias FASTA asociadas a los genes humanos de BRCA1, BRCA2 y HOXB13:

3) Cuando se quiere ejecutar una serie de comandos de forma secuencial en el terminal bash, se crea un script o protocolo y se guarda en un archivo de texto con extensión «.sh». Este script nos permite referirnos internamente a sus parámetros de manera genérica, lo que significa que puede funcionar en cualquier grupo de argumentos del mismo tipo. Además, para hacerlo más flexible, se deben especificar estos parámetros genéricos dentro del script, de manera que cuando se invoque el script desde la línea de comandos, podemos sustituir estos parámetros genéricos por valores específicos proporcionados por el usuario junto con el nombre del comando. Al utilizar este enfoque, se pueden automatizar tareas repetitivas o procesos complejos, lo que hace que el trabajo sea más eficiente y consistente.

$ vi analiza_fasta.sh

4) Antes de introducir el código para generar un protocolo, dos consideraciones a tener en cuenta:

  • En la primera línea del protocolo se ha de indicar, siempre, el intérprete de comandos bash (GNU Bourne-Again SHell). En la mayoría de los sistemas coexisten otros intérpretes como sh (Bourne) o csh (C shell). El directorio donde se localiza el intérprete se escribe a continuación del conjunto de símbolos#!
  • Para introducir comentarios en el protocolo se ha de introducir el símbolo# (en inglés, shebang) en la primera columna del fichero.

5) Escribe cada una de las siguientes líneas en el fichero sh que acabas de abrir. Debes escribir en modo insert, lo primero que tienes que hacer es teclear la letra i, y a continuación escribe las siguientes líneas:

#!/bin/bash

# Este protocolo analiza un fichero que contiene una única secuencia FASTA

# Primero, se chequea si se suministra el nombre del fichero como argumento

if [ $# -eq 0 ]

then

    echo "Por favor, suministra un nombre de fichero como argumento"

    exit 1

fi

# El símbolo $$ indica el PID del proceso

echo "El valor del PID del proceso es";

echo "PID es $$";

# $1 representa el primer argumento a analizar. En este caso el nombre del fichero FASTA

echo "El tamaño del fichero FASTA es:";

ls -sh $1 | gawk '{print $1}';

echo "Número de líneas del fichero FASTA:";

wc -l $1 | gawk '{ print $1 }';

echo "Extrae las primeras siete líneas del fichero";

head -7 $1;

# Las siguientes dos líneas considera comentarlas, si la secuencia FASTA tiene muchas líneas

echo "Extrae la secuencia del fichero FASTA";

sequence=$(awk '/^>/ {next} {printf "%s", $0} END {print ""}' "$1")

echo "$sequence"

# Cálculo de la longitud de la secuencia

length=$(echo -n "$sequence" | wc -c)

echo " Longitud de la secuencia: $length nucleotidos"

# Cuenta el número de nucleótidos que tiene la secuencia

num_A=$(grep -o 'A' <<< "$sequence" | wc -l)

num_C=$(grep -o 'C' <<< "$sequence" | wc -l)

num_G=$(grep -o 'G' <<< "$sequence" | wc -l)

num_T=$(grep -o 'T' <<< "$sequence" | wc -l)

# Se han generado in situ 4 nuevas variables. Imprime cada número de nucleótidos

echo "Numero de nuclotido A: $num_A"

echo "Numero de nuclotido C: $num_C"

echo "Numero de nuclotido G: $num_G"

echo "Numero de nuclotido T: $num_T"

# Cálculo del contenido GC de la secuencia

num_GC=$((num_C + num_G))

total=$((num_A + num_C + num_G + num_T))

gc_content=$(bc -l <<< "scale=2; $num_GC / $total * 100")

echo "GC contenido: $gc_content%"

# Identificación de los ORFs de la secuencia

echo "Identificando ORFs..."

ORFs=$(echo -n "$sequence" | tr 'ATCG' 'tacg' | grep -Eo '(atg([acgt]{3})*?(taa|tag|tga))+' | tr 'tacg' 'ATCG')



if [ -z "$ORFs" ]

then

    echo "No se encuentran ORFs"

else

    num_ORFs=$(echo -n "$ORFs" | awk '{print length}' | wc -l)

    echo "Numero de ORFs: $num_ORFs"

    echo "ORFs: $ORFs"

fi

Salva el fichero que se ha creado escribiendo :wq! analiza_fasta.sh

6) Para ejecutar el script, salva el anterior fichero con la extensión ".sh" y hazlo ejecutable con el comando chmod +x. Ejecútalo con el nombre del fichero FASTA a analizar:

$ pwd
/home/student/fasta_sequence
 $ chmod +x analiza_fasta.sh
$ ./analiza_fasta.sh AC060780.18.fasta

7) Hasta ahora se ha generado un protocolo para analizar ficheros FASTA, se ha ejecutado y comprobado que funciona. El siguiente paso es ejecutar el anterior fichero de análisis en un directorio con diferentes secuencias. Para ello, se genera otro protocolo que incluya el anterior. El nuevo protocolo se llama analiza_fasta_dir.sh. Los pasos para seguir son:

$ pwd
/home/student
$ vi analiza_fasta_dir.sh

Las órdenes que hay que introducir en este fichero son:

#! /bin/bash

echo "Se inicia la ejecución con el PID $$";

echo "Número de argumentos a analizar $#";

echo "El nombre del directorio a analizar $1";

echo "Los nombres de los ficheros que se analizan son";

ls $1;

echo "Ejecución del protocolo de análisis FASTA para cada uno de los ficheros en el directorio";

ls $1 |    while read file;

     do

          echo "ejecución analiza_fasta.sh $file";

          ./analiza_fasta.sh $1/$file;

     done

Salva el fichero que se ha creado escribiendo :wq! analiza_fasta_dir.sh

8) Para ejecutar el script, salva el anterior fichero con la extensión.sh y hazlo ejecutable con el comando chmod +x . Ejecútalo con el nombre del directorio que contiene los ficheros FASTA a analizar:

$ pwd
/home/student
$ cp fasta_sequence/analiza_fasta.sh .
$ chmod +x analita_fasta_dir.sh
$ ./analiza_fasta_dir.sh fasta_sequence

Se puede observar que los protocolos que se ejecutan se encuentran en el directorio actual de trabajo (./) y se añade el anterior símbolo en lugar de solo invocar su nombre. Sin embargo, una vez que se está seguro de que el script funciona correctamente, es más conveniente guardar toda nuestra colección de protocolos en un solo directorio del sistema. De esta manera, no se han de mantener múltiples copias y se podrán ejecutar desde cualquier lugar en nuestro árbol de directorios.

Las plataformas Gnu/Linux tienen un conjunto de variables globales que contienen datos de carácter general. Se resumen en la siguiente tabla, la tabla 16.

Tabla 16. Comandos para la ejecución de scripts.

Comando Descripción
set Establece valores que serán usados por los programas, aplicación, scripts
echo Imprime lo que se le encarga que haga
printenv Lista la lista completa de variables de entorno de tu versión Gnu/Linux
which Localiza los archivos ejecutables de una determinada aplicación
export Crea/modifica una variable del sistema

Fuente: elaboración propia.

El comando set en Gnu/Linux muestra y establece variables de entorno para la sesión actual. Se utiliza para ver el valor de las variables de entorno del sistema y también para asignar valores a nuevas variables de entorno. El comando echo, por otro lado, se utiliza para mostrar mensajes de texto o el valor de las variables en la pantalla. También se puede utilizar para escribir texto en archivos o para concatenar varios mensajes de texto.

La ventaja de utilizar echo es que permite seleccionar y mostrar solo la información que se necesita, lo que hace que sea más fácil de leer y entender. Por otro lado, la ventaja de utilizar set es que permite establecer y modificar variables de entorno, lo que puede ser útil al automatizar tareas y scripts en Gnu/Linux.

Abre un terminal de Gnu/Linux. Puedes ver la lista completa de variables de entorno de tu versión de Gnu/Linux utilizando el comando printenv. Puedes tener una lista más manejable añadiendo diferentes comandos:

$printenv | less

Cada línea contiene el nombre de la variable de entorno Gnu/Linux seguido de = y del valor. Por ejemplo:

HOME=/home/student

Esto quiere decir que HOME es una variable de entorno de Gnu/Linux que tiene el valor establecido como directorio /home/student.

Las variables de entorno suelen estar en mayúsculas, aunque también puedes crear variables de entorno en minúsculas. La salida de printenv muestra todas las variables de entorno en mayúsculas. Una cosa importante para tener en cuenta es que las variables de entorno de Gnu/Linux distinguen entre mayúsculas y minúsculas. Si deseas ver el valor de una variable de entorno específica, puedes hacerlo considerando el nombre de esa variable como argumento del comando printenv. La cadena de caracteres completa se vería así en la línea de comando:

$ printenv HOME
/home/student
$ echo $USER
student

La sintaxis básica para crear una variable de entorno en Gnu/Linux es la siguiente. Es fácil lograrlo, solo se necesita especificar un nombre y un valor. Seguiremos la convención de mantener todas las letras en mayúsculas para el nombre de la variable, y la estableceremos como una cadena simple.

$ HIB_VAR='BioInformatica y BioEstadistica!'
$ export HIB_VAR
$ export HIB_VAR='BioInformatica y BioEstadistica!'    #en una única línea

Se han usado comillas simples, ya que el valor de la variable contiene un espacio. Además, se han utilizado comillas simples porque el signo de exclamación es un carácter especial en la shell bash que normalmente se expande al historial de bash si no se escapa o se coloca entre comillas simples. Ahora tenemos una variable de shell. Esta variable está disponible en nuestra sesión actual, pero no se transmite a los procesos secundarios.

Se puede comprobar, buscando nuestra nueva variable dentro de la salida de set:

$ set | grep HIB_VAR
HIB_VAR='BioInformartica y BioEstadistica!'

Si la variable se ha definido correctamente, podrás utilizarla en cualquier protocolo que ejecutes en la misma sesión del terminal. Por ejemplo, si creas un archivo de script en bash que requiere utilizar la variable HIB_VAR, simplemente puedes referirte a ella utilizando el símbolo $. Por ejemplo, si tu archivo de script se llama myscript.sh y contiene el siguiente código:

#! /bin/bash

echo " El valor de HIB_VAR es: $HIB_VAR"

Si se ejecuta el archivo de script en la misma sesión del terminal utilizando el comando bash,

$ chmod +x myscript.sh
$ bash myscript.sh
BioInformatica y Bioestadistica!

el archivo de script debería imprimir el valor de la variable HIB_VAR que definiste previamente. Para revertir el valor de una variable se puede usar el comando unset.

$ echo $HIB_VAR
BioInformartica y BioEstadistica!
$ unset HIB_VAR
$ echo $HIB_VAR

Por otra parte, ten en cuenta que, si cierras la sesión del terminal y la vuelves a abrir, tendrás que volver a definir la variable local utilizando el comando export. Para evitar esto, puedes agregar la definición de la variable HIB_VAR a tu archivo de inicio de bash (por ejemplo, ~/.bashrc), de modo que la variable esté disponible cada vez que inicies una nueva sesión del terminal.

El comando which es una herramienta que permite encontrar rápidamente los archivos ejecutables de una determinada aplicación y localiza los ficheros ejecutables mediante la variable de entorno PATH.

$ which nano docker gawk
/usr/bin/nano

/usr/bin/docker

/usr/bin/gawk

Finalmente, se define la variable PATH. El contenido de la variable PATH es una cadena que contiene paths de directorios separados por dos puntos, y estos son los directorios en los que el shell busca el comando que el usuario escribe desde el teclado.

$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:
/usr/games:/usr/local/games:/snap/bin

La búsqueda no se realiza en el orden en el que están los directorios en la variable PATH. Cuando se escribe un comando el shell buscará primero en /usr/local/bin, luego en /usr/bin, a continuación, en /usr/games y finalmente en /snap/bin. Desde el momento en que el shell encuentra el comando, detiene la búsqueda y ejecuta el comando encontrado. Podemos escribir un comando utilizando:

  • Su nombre:
    El path absoluto (/bin/cat /etc/passwd ).
    El path relativo (utilizando «.» o «..» en general para los programas o scripts que no se encuentran en PATH).
    Se puede añadir un directorio a la variable PATH, añadamos el directorio donde se encuentran todos los scripts que se generen.
  • Únicamente para la sesión activa:
    Si deseas añadir, por ejemplo: /home/student/HIB_scripts a la variable PATH, escribe en el shell lo siguiente según el caso.
    # Para tener el directorio al final del PATH:

    $ export PATH=$PATH:/home/student/HIB_scripts

    # Para tener el directorio al inicio del PATH:

    $ export PATH=/home/student/HIB_scripts/:$PATH

    Ahora puedes utilizar el programa escribiendo simplemente su nombre. Al desconectarse, PATH retomará a su valor por defecto, entonces /home/student/HIB_scripts no existirá más.

  • De manera permanente:
    Si deseas configurar PATH de forma permanente debes editar el archivo de configuración de su shell de conexión. Como por lo general el shell bash es el más utilizado, debes editar el archivo: /home/user/.bashrc. El comando entonces sería:

    $ echo 'export PATH=$PATH:/home/student/HIB_scripts' >> /home/user/.bashrc

    Después de esto, en cada conexión la variable PATH contendrá el directorio /home/student HIB_scripts. Esta operación puede ser ejecutada por el usuario student, no se necesitan los permisos de root.