1.12: Miscelánea
- Page ID
- 55191
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\( \newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\)
( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\)
\( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)
\( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\)
\( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)
\( \newcommand{\Span}{\mathrm{span}}\)
\( \newcommand{\id}{\mathrm{id}}\)
\( \newcommand{\Span}{\mathrm{span}}\)
\( \newcommand{\kernel}{\mathrm{null}\,}\)
\( \newcommand{\range}{\mathrm{range}\,}\)
\( \newcommand{\RealPart}{\mathrm{Re}}\)
\( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)
\( \newcommand{\Argument}{\mathrm{Arg}}\)
\( \newcommand{\norm}[1]{\| #1 \|}\)
\( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)
\( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\AA}{\unicode[.8,0]{x212B}}\)
\( \newcommand{\vectorA}[1]{\vec{#1}} % arrow\)
\( \newcommand{\vectorAt}[1]{\vec{\text{#1}}} % arrow\)
\( \newcommand{\vectorB}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vectorC}[1]{\textbf{#1}} \)
\( \newcommand{\vectorD}[1]{\overrightarrow{#1}} \)
\( \newcommand{\vectorDt}[1]{\overrightarrow{\text{#1}}} \)
\( \newcommand{\vectE}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash{\mathbf {#1}}}} \)
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\(\newcommand{\avec}{\mathbf a}\) \(\newcommand{\bvec}{\mathbf b}\) \(\newcommand{\cvec}{\mathbf c}\) \(\newcommand{\dvec}{\mathbf d}\) \(\newcommand{\dtil}{\widetilde{\mathbf d}}\) \(\newcommand{\evec}{\mathbf e}\) \(\newcommand{\fvec}{\mathbf f}\) \(\newcommand{\nvec}{\mathbf n}\) \(\newcommand{\pvec}{\mathbf p}\) \(\newcommand{\qvec}{\mathbf q}\) \(\newcommand{\svec}{\mathbf s}\) \(\newcommand{\tvec}{\mathbf t}\) \(\newcommand{\uvec}{\mathbf u}\) \(\newcommand{\vvec}{\mathbf v}\) \(\newcommand{\wvec}{\mathbf w}\) \(\newcommand{\xvec}{\mathbf x}\) \(\newcommand{\yvec}{\mathbf y}\) \(\newcommand{\zvec}{\mathbf z}\) \(\newcommand{\rvec}{\mathbf r}\) \(\newcommand{\mvec}{\mathbf m}\) \(\newcommand{\zerovec}{\mathbf 0}\) \(\newcommand{\onevec}{\mathbf 1}\) \(\newcommand{\real}{\mathbb R}\) \(\newcommand{\twovec}[2]{\left[\begin{array}{r}#1 \\ #2 \end{array}\right]}\) \(\newcommand{\ctwovec}[2]{\left[\begin{array}{c}#1 \\ #2 \end{array}\right]}\) \(\newcommand{\threevec}[3]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \end{array}\right]}\) \(\newcommand{\cthreevec}[3]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \end{array}\right]}\) \(\newcommand{\fourvec}[4]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \\ #4 \end{array}\right]}\) \(\newcommand{\cfourvec}[4]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \\ #4 \end{array}\right]}\) \(\newcommand{\fivevec}[5]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \\ #4 \\ #5 \\ \end{array}\right]}\) \(\newcommand{\cfivevec}[5]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \\ #4 \\ #5 \\ \end{array}\right]}\) \(\newcommand{\mattwo}[4]{\left[\begin{array}{rr}#1 \amp #2 \\ #3 \amp #4 \\ \end{array}\right]}\) \(\newcommand{\laspan}[1]{\text{Span}\{#1\}}\) \(\newcommand{\bcal}{\cal B}\) \(\newcommand{\ccal}{\cal C}\) \(\newcommand{\scal}{\cal S}\) \(\newcommand{\wcal}{\cal W}\) \(\newcommand{\ecal}{\cal E}\) \(\newcommand{\coords}[2]{\left\{#1\right\}_{#2}}\) \(\newcommand{\gray}[1]{\color{gray}{#1}}\) \(\newcommand{\lgray}[1]{\color{lightgray}{#1}}\) \(\newcommand{\rank}{\operatorname{rank}}\) \(\newcommand{\row}{\text{Row}}\) \(\newcommand{\col}{\text{Col}}\) \(\renewcommand{\row}{\text{Row}}\) \(\newcommand{\nul}{\text{Nul}}\) \(\newcommand{\var}{\text{Var}}\) \(\newcommand{\corr}{\text{corr}}\) \(\newcommand{\len}[1]{\left|#1\right|}\) \(\newcommand{\bbar}{\overline{\bvec}}\) \(\newcommand{\bhat}{\widehat{\bvec}}\) \(\newcommand{\bperp}{\bvec^\perp}\) \(\newcommand{\xhat}{\widehat{\xvec}}\) \(\newcommand{\vhat}{\widehat{\vvec}}\) \(\newcommand{\uhat}{\widehat{\uvec}}\) \(\newcommand{\what}{\widehat{\wvec}}\) \(\newcommand{\Sighat}{\widehat{\Sigma}}\) \(\newcommand{\lt}{<}\) \(\newcommand{\gt}{>}\) \(\newcommand{\amp}{&}\) \(\definecolor{fillinmathshade}{gray}{0.9}\)Herramientas como sort
, head
and tail
, grep
, awk
y sed
representan una poderosa caja de herramientas, especialmente cuando se usan con las corrientes de entrada estándar y salida estándar. Hay muchas otras utilidades útiles de línea de comandos, y cubriremos algunas más, pero no necesitamos pasar tanto tiempo con ellas como lo hemos hecho para awk
y sed
.
Manipulación de saltos de línea
Todas las características de las herramientas que hemos cubierto hasta ahora asumen la línea como la unidad básica de procesamiento; awk
procesa columnas dentro de cada línea, sed
coincide y reemplaza patrones en cada línea (pero no fácilmente a través de líneas), y así sucesivamente. Desafortunadamente, a veces la forma en que los datos se rompen sobre las líneas no es conveniente para estas herramientas. La herramienta tr
traduce conjuntos de caracteres en su entrada a otro conjunto de caracteres como se especifica:... | tr '' ''
<set1><set2>[1]
Como breve ejemplo, tr 'TA' 'AT' Pz_CDNAS.fasta
traduciría todos los caracteres T
a caracteres A
, y viceversa (esto va por cada T
y A
en el archivo, incluidos los de las líneas de encabezado, por lo que esta herramienta no sería muy útil para manipular FASTA). En cierto modo, tr
es como un simple sed
. El mayor beneficio es que, a diferencia de sed
, tr
no rompe su entrada en una secuencia de líneas que se operan individualmente, sino que toda la entrada se trata como una sola corriente. Así tr
puede reemplazar los caracteres especiales de “nueva línea” que codifican el final de cada línea con algún otro carácter.
En la línea de comandos, dichos caracteres de nueva línea pueden representarse como\ n
, por lo que un archivo con las siguientes tres líneas

podría representarse alternativamente como línea 1\ nlínea 2\ nlínea 3\ n
(la mayoría de los archivos terminan con un carácter final de nueva línea). Suponiendo que este archivo se llamara lines.txt
, podríamos reemplazar todas las\ n
nuevas líneas con #
caracteres.

Observe en lo anterior que incluso la nueva línea final ha sido reemplazada, y nuestro símbolo del sistema impreso en la misma línea que la salida. Del mismo modo, tr
(y sed
) pueden reemplazar caracteres con nuevas líneas, por lo que tr '#' '\ n'
desharía lo anterior.
Usar tr
en combinación con otras utilidades puede ser útil, particularmente para formatos como FASTA, donde un solo “registro” se divide en varias líneas. Supongamos que queremos extraer todas las secuencias de pz_CDNAS.fasta
con NREAD mayores a 5. La estrategia sería algo así como:
- Identificar un carácter que no esté presente en el archivo, tal vez un carácter
@
o tabulador\ t
(y verifique congrep
para asegurarse de que no esté presente antes de continuar). - Usa
tr
para reemplazar todas las nuevas líneas con ese carácter, por ejemplo,tr '\ n'' @ '
. - Debido a que se utilizan
>
caracteres para indicar el inicio de cada registro en archivos FASTA, usesed
para reemplazar inicio de registro>
caracteres con nuevas líneas seguidas de esos caracteres:sed -r 's/>/\ n>/g'
.En este punto, el flujo se vería así, donde cada línea representa un solo registro de secuencia (con
@
caracteres extraños insertados): - Use
grep
,sed
,awk
, y así sucesivamente para seleccionar o modificar solo esas líneas de interés. (Si es necesario, también podríamos usarsed
para eliminar los caracteres@
insertados para que podamos procesar en la secuencia misma). Para nuestro ejemplo, usased -r 's/=/ /1 '| awk' {if ($3 > 5) {print $0}} '
para imprimir solo líneas donde el nReading sea mayor que 5. - Vuelva a formatear el archivo a FASTA reemplazando los caracteres
@
por líneas nuevas, contr
osed
. - El flujo resultante tendrá líneas en blanco adicionales como resultado de las nuevas líneas adicionales insertadas antes de cada carácter
>
. Estos se pueden quitar de diversas maneras, incluyendoawk '{if (NF > 0) print $0}'
.
Unir archivos en una columna común (y tareas relacionadas de fila/columna)
A menudo, la información con la que queremos trabajar se almacena en archivos separados que comparten una columna común. Considere el resultado de usar blastx
para identificar las HSP superiores contra el conjunto de marcos de lectura abiertos de levadura, por ejemplo.

El archivo resultante pz_blastx_yeast_top1.txt
contiene la información estándar de BLAST:

Del mismo modo, podemos guardar una tabla de información de secuencia del programa fasta_stats
con las líneas de comentario eliminadas como pz_stats.table
.

Visualización del archivo con menos -S
:

Dados estos datos, podríamos preguntar qué secuencias tuvieron un impacto en un marco de lectura abierto de levadura y un contenido de GC de más del 50%. Podríamos averiguarlo fácilmente con awk
, pero primero necesitamos invocar join
, que fusiona dos archivos de texto fila/columna basados en líneas con valores similares en una columna de “clave” especificada. Por defecto, unir
solo da salida a filas donde los datos están presentes en ambos archivos. Se requiere que ambos archivos de entrada estén ordenados de manera similar (ya sea ascendente o descendente) en las columnas clave: join -1 -2
<key column in file1><key column in file2><file1><file2>.
Como la mayoría de las herramientas, unir
salidas su resultado a salida estándar, que puede ser redirigido a un archivo u otras herramientas como less
y awk
. Idealmente, nos gustaría decir join -1 1 -2 1 pz_stats.txt pz_blastx_yeast_top1.txt
para indicar que deseamos unir estos archivos por su primera columna común, pero hasta el momento los archivos no están ordenados de manera similar. Entonces, primero crearemos versiones ordenadas.

Ahora podemos ejecutar nuestro join -1 1 -2 1 pz_stats.sorted.txt pz_blastx_yeast_top1.sorted.txt
, canalizando el resultado en menos
. La salida contiene todas las columnas del primer archivo, seguidas de todas las columnas del segundo archivo (sin la columna clave), separadas por espacios únicos.

En lugar de ver la salida con menos
, canalizarla en un awk '{if ($1 > 0.5) print $1}'
identificaría rápidamente esas secuencias con coincidencias BLAST y contenido GC superior al 50%.
Una dificultad con la salida anterior es que es bastante difícil de leer, al menos para nosotros los humanos. La misma queja podría hacerse para la mayoría de los archivos que están separados por caracteres de tabulación; debido a la forma en que las pestañas se formatean en herramientas menos
y similares, las entradas de diferentes longitudes pueden hacer que las columnas se desalineen (solo visualmente, por supuesto). La utilidad de columna
ayuda en algunos casos. Reformatea la entrada de fila/columna separada por espacios en blanco para que la salida sea legible por humanos, reemplazando uno o más espacios y tabulaciones por un número apropiado de espacios para que las columnas estén alineadas visualmente: columna -t
<file>o... | columna -t
.
A estas alturas, no debería sorprendernos que la columna
escriba su salida a la salida estándar. Aquí está el resultado de join -1 1 -2 1 pz_stats.sorted.txt pz_blastx_yeast_top1.sorted.txt | column -t | less -S
, que contiene los mismos datos que los anteriores, pero con espacios utilizados para rellenar las columnas apropiadamente.

Debido a que la mayoría de las herramientas como awk
y sort
utilizan cualquier número de caracteres de espacios en blanco como delimitadores de columna, también se pueden usar en la columna
de datos.
Hay varias advertencias importantes al usar join
. Primero, si se repite alguna entrada en las columnas clave, la salida contendrá una fila por cada par de claves coincidentes.

En segundo lugar, los archivos deben clasificarse de manera similar; si no lo están, unir
producirá en el mejor de los casos una advertencia difícil de ver. Un truco útil al usar shells compatibles con bash
es hacer uso de las características para la “sustitución de procesos”. Básicamente, cualquier comando que se imprima en la salida estándar puede envolverse en < (
y)
y usarse en lugar de un nombre de archivo: el shell creará automáticamente un archivo temporal con el contenido de la salida estándar del comando y reemplazará la construcción con el nombre de archivo temporal. Este ejemplo une los dos archivos como antes, sin pasos de ordenación separados: join -1 1 -2 1 < (sort -k1,1d pz_stats.txt) < (sort -k1,1d pz_blastx_yeast_top1.txt) < (sort -k1,1d)
. Porque el archivo pz_stats.txt
fue el resultado de redirigir la salida estándar de. /fasta_stats pz_cDNAs.txt
a través de grep -v '#'
, podríamos decir equivalentemente join -1 1 -2 1 < (. /fasta_stats pz_cdnas.fasta | grep -v '#' | sort -k1,1d) < (sort -k1,1d pz_blastx_yeast_top1.txt)
.
Por último, a menos que estemos dispuestos a suministrar un número desmesurado de argumentos, el valor por defecto para unir
es producir solo líneas donde la información clave se encuentre en ambos archivos. Más a menudo, podríamos desear que se incluyan todas las claves, con valores “faltantes” (por ejemplo, NA
) asumidos para los datos presentes en un solo archivo. En el lenguaje de bases de datos, estas operaciones se conocen como “unión interna” y “unión externa completa” (o simplemente “unión externa”), respectivamente.

Donde unir
no produce fácilmente uniones externas, herramientas más sofisticadas pueden hacer esto y mucho más. Por ejemplo, los lenguajes de programación Python y R (cubiertos en capítulos posteriores) sobresalen en la manipulación y fusión de colecciones de datos tabulares. Otras herramientas utilizan un lenguaje especializado para la manipulación de bases de datos conocido como Lenguaje de Consulta Estructurado o SQL. Dichas bases de datos a menudo se almacenan en formato binario, y éstas se consultan con software como MySQL y Postgres (ambos requieren acceso de administrador para administrar), o motores más simples como sqlite3
(que pueden ser instalados y administrados por usuarios normales). [2]
Recuento de líneas duplicadas
Vimos que ordenar
con la bandera -u
se puede usar para eliminar duplicados (definidos por las columnas clave utilizadas). ¿Qué hay de aislar duplicados, o de otra manera contarlos o identificarlos? Lamentablemente, ordenar
no está a la altura de la tarea, pero una herramienta llamada uniq
puede ayudar. Se colapsa líneas consecutivas, idénticas. Si se usa el indicador -c
, antepone cada línea con el número de líneas colapsadas: uniq
<file>o... | uniq
.
Debido a que uniq
considera líneas enteras en sus comparaciones, es algo más rígido que sort -u
; no hay forma de especificar que solo se deben usar ciertas columnas en la comparación. [3] La utilidad uniq
también solo colapsará líneas idénticas si son consecutivas, lo que significa que la entrada ya debería estar ordenada (a menos que el objetivo realmente sea fusionar solo líneas duplicadas ya consecutivas). Así, para identificar duplicados, la estrategia suele ser:
- Extraer columnas de interés usando
awk
. - Ordenar el resultado usando
sort
. - Use
uniq -c
para contar duplicados en las líneas resultantes.
Consideremos nuevamente la salida de. /fasta_stats pz_cdnas.fasta
, donde la columna 4 enumera los 5-meros más comunes para cada secuencia. Usando este patrón de extracto/clasificación/uniq, podemos identificar rápidamente cuántas veces se listó cada 5-mer.

El resultado enumera los recuentos para cada 5-mer. Podríamos continuar clasificando la salida por la nueva primera columna para identificar los 5-meros con los recuentos más grandes.

A menudo es útil ejecutar uniq -c
en listas de recuentos producidos por uniq -c
. Ejecutar el resultado anterior a través de awk '{print $1}' | sort -k1,1n | uniq -c
revela que 90 5-mers se enumeran una vez, 18 se enumeran dos veces, y así sucesivamente.

Contar artículos con uniq -c
es una técnica poderosa para los datos de “comprobación de la cordura”. Si queremos comprobar que una columna o combinación de columnas dada no tiene entradas duplicadas, por ejemplo, podríamos aplicar la estrategia extract/sort/uniq seguida de awk '{if ($1 > 1) print $0}'
. Del mismo modo, si queremos asegurarnos de que todas las filas de una tabla tengan el mismo número de columnas, podríamos ejecutar los datos a través de awk '{print NF}'
para imprimir el número de columnas en cada fila y luego aplicar extracto/sort/uniq, esperando que todos los recuentos de columnas se colapsen en una sola entrada.
Trazado básico con gnuplot
Más ilustrando el poder de awk
, sed
, sort
y uniq
, podemos crear un “histograma” basado en texto de coberturas para las secuencias en el archivo Pz_CDNAS.fasta
, que se almacenan en la tercera columna de las líneas de encabezado (por ejemplo, >PZ 7180000000004_TX nReads=26 cov=9.436
). Comenzaremos aislando los números de cobertura con grep
(para seleccionar solo líneas de encabezado), sed
(para reemplazar =
caracteres con espacios) y awk
(para extraer la nueva columna de números de cobertura), mientras simultáneamente imprimimos solo la porción entera de la cobertura columna.

La salida es una columna simple de enteros, que representa coberturas redondeadas. A continuación, una especie -k1,1n | uniq -c
producirá los recuentos para cada bin de cobertura, revelando que la mayoría de las secuencias (281) están en cobertura 1X, un puñado están en 2X y 3X, y las coberturas más altas son cada vez más raras.

Aunque lenguajes como Python y R proporcionan paquetes de trazado de datos fáciles de usar, a veces puede ser útil trazar rápidamente un conjunto de datos en la línea de comandos. El programa gnuplot
puede producir no solo formatos de imagen como PNG y PDF, sino también salida basada en texto directamente a salida estándar. Aquí está el comando para trazar el histograma anterior (pero con puntos, en lugar de los cuadros tradicionales), junto con la salida.

Es un poco difícil de ver, pero los puntos trazados están representados por caracteres
A. Desglosando el comando gnuplot
, set term dumb
instruye a gnuplot
para producir salida basada en texto, plot “-”
indica que queremos trazar datos del flujo de entrada estándar, usar 2:1
indica que los valores X deben ser dibujados de la segunda columna y los valores Y de la primera, y con puntos
especifica que los puntos, a diferencia de líneas o cajas, deben dibujarse. Debido a que los recuentos de coberturas caen tan rápidamente, es posible que queramos producir una gráfica de registro/registro, y también podemos agregar un título: gnuplot -e 'set term dumb; set logscale xy; plot “-” usando 2:1 con points' title “Coverage Counts”

Aunque solo hemos mostrado el uso más básico de gnuplot
, en realidad es un paquete de trazado sofisticado: los diversos comandos normalmente no se especifican en la línea de comandos sino que se colocan en un script ejecutable. Para una demostración de sus capacidades, visite http://gnuplot.info.
For-Loops en bash
A veces queremos ejecutar el mismo comando o comandos similares como un conjunto. Por ejemplo, podemos tener un directorio lleno de archivos que terminan en .tmp
, pero deseábamos que terminaran en .txt
.

Debido a la forma en que funcionan los comodines de línea de comandos, no podemos usar un comando como mv *.tmp *.txt
; el *.tmp
se expandiría en una lista de todos los archivos, y *.txt
se expandiría en nada (ya que no coincide con ningún nombre de archivo existente).
Afortunadamente, bash
proporciona una construcción de looping, donde los elementos reportados por comandos (como ls *.tmp
) están asociados con una variable (como $i
), y otros comandos (como mv $i $i.txt
) se ejecutan para cada elemento.

Es más común ver tales bucles en scripts ejecutables, con la estructura de control rota en varias líneas.

Esta solución funciona, aunque a menudo las técnicas de programación similares (como las sentencias if) en bash
se vuelven engorrosas, y usar un lenguaje más robusto como Python puede ser la mejor opción. Sin embargo, bash
tiene un truco más interesante bajo la manga: el shell bash
puede leer datos en la entrada estándar, y al hacerlo intenta ejecutar cada línea. Entonces, en lugar de usar un for-loop explícito, podemos usar herramientas como awk
y sed
para “construir” comandos como líneas. Eliminemos el .tmp
de la mitad de los archivos construyendo comandos mv
sobre la base de una entrada inicial de ls -1 *.tmp*
(que enumera todos los archivos que coinciden con *.tmp*
en una sola columna). Primero, construiremos la estructura de los comandos.

A esto agregaremos un sed -r s/\ .tmp//2
para reemplazar la segunda instancia de .tmp
por nada (recordando escapar el punto en la expresión regular), dando como resultado líneas como

Después del sed
, canalizaremos esta lista de comandos a bash
, y nuestro objetivo se logra.

Control de versiones con git
En el capítulo 6, “Instalación de software (Bioinformática)”, trabajamos en un proyecto bastante sofisticado, que implica instalar software (en nuestro directorio $HOME/local/bin
) así como descargar archivos de datos y escribir scripts ejecutables (lo que hicimos en nuestro directorio $HOME/projects/P450s
). En particular, inicialmente creamos un script para automatizar la ejecución de HMMER en algunos archivos de datos, llamado runhmmer.sh
. Aquí están los contenidos del directorio del proyecto cuando lo vimos por última vez:

Puede ser que a medida que continuemos trabajando en el proyecto, hagamos ajustes al script runhmmer.sh
u otros archivos de texto en este directorio. Idealmente, podríamos acceder a versiones anteriores de estos archivos, en caso de que necesitemos referirnos por razones de procedencia o queremos deshacer ediciones posteriores. Una forma de lograr esta tarea sería crear frecuentemente copias de seguridad de archivos importantes, tal vez con nombres de archivo incluyendo la fecha de la copia de seguridad. Sin embargo, esto rápidamente se volvería difícil de manejar.
Una alternativa es usar el control de versiones, que es un sistema para administrar cambios en archivos (especialmente programas y scripts) a lo largo del tiempo y entre diversos contribuyentes a un proyecto. Por lo tanto, un sistema de control de versiones permite al usuario registrar cambios en archivos a lo largo del tiempo, e incluso permite que varios usuarios registren cambios, proporcionando la capacidad de examinar las diferencias entre las distintas ediciones. Hay una serie de programas populares de control de versiones, como svn
(subversion) y cvs
(sistema de versionado concurrente). Debido a que el trabajo de rastrear los cambios en los archivos a lo largo del tiempo y los usuarios es bastante complejo (especialmente cuando varios usuarios pueden estar realizando ediciones independientes simultáneamente), el uso del software de control de versiones puede ser un gran conjunto de habilidades en sí mismo.
Uno de los sistemas de control de versiones desarrollados más recientemente es git
, que ha ganado popularidad por varias razones, incluido su uso en la gestión de proyectos de software populares como el kernel de Linux. [4] El sistema git
(que es administrado por un programa llamado git
) usa una serie de palabras de vocabulario que debemos definir primero.
-
Repositorio
- También conocido como “repositorio”, un repositorio
git
suele ser solo una carpeta/directorio.
- También conocido como “repositorio”, un repositorio
-
Versión
- Una versión es efectivamente una instantánea de un conjunto seleccionado de archivos o directorios en un repositorio. Por lo tanto, puede haber múltiples versiones de un repositorio a través del tiempo (o incluso creadas independientemente por diferentes usuarios).
-
Comprometer
- Confirmar es la acción de almacenar un conjunto de archivos (en un repositorio) en una versión.
-
Diff
- Dos versiones diferentes pueden ser “diffedadas”, lo que significa revelar los cambios entre ellas.
-
Etapa
- No todos los archivos necesitan ser incluidos en una versión; la puesta en escena de un conjunto de archivos los marca para su inclusión en la versión cuando ocurre la siguiente entrega.
El sistema git
, como todos los sistemas de control de versiones, es bastante complejo y proporciona muchas características. Los fundamentos, sin embargo, son: (1) hay una carpeta que contiene el proyecto de interés; (2) los cambios en algunos archivos se hacen a lo largo del tiempo; (3) los archivos editados pueden ser “escenificados” periódicamente; y (4) un “commit” incluye una instantánea de todos los archivos por etapas y almacena la información en una “versión”. (Para que conste, toda esta información se almacena en un directorio oculto creado dentro del directorio del proyecto llamado .git
, que es administrado por el propio programa git
).
Para ilustrar, vamos a crear un repositorio para el proyecto p450s
, editar el archivo de script runhmmer.sh
así como crear un archivo README.txt
, y confirmar esos cambios. Primero, para convertir un directorio en un repositorio git
, necesitamos ejecutar git init
:

Este paso crea el directorio oculto.git
que contiene los archivos requeridos para su seguimiento por parte del sistema. Normalmente no necesitamos trabajar directamente con este directorio, el software git
lo hará por nosotros. A continuación, crearemos nuestra primera versión poniendo en escena nuestros primeros archivos y ejecutando nuestro primer commit. Podríamos mantener versiones rastreadas de todos los archivos de este directorio, pero ¿queremos? Los archivos de datos como dmel-all-translation-r6.02.fasta
son grandes y es poco probable que cambien, por lo que registrarlos sería innecesario. Del mismo modo, debido a que el archivo de salida p450s_hmmsearch_dmel.txt
se genera mediante programación y siempre se puede regenerar (si tenemos una versión del programa que lo creó), tampoco haremos un seguimiento de eso. Para “organizar” archivos para la siguiente confirmación, usamos git add
; para organizar todos los archivos en el directorio del proyecto, usaríamos git add -A
, pero aquí queremos poner en escena solo runhmmer.sh
, así ejecutaremos git add runhmmer.sh
.

No se ha impreso ningún mensaje, pero en cualquier momento podemos ver el estado del proceso git
ejecutando git status
.

La información de estado muestra que tenemos un nuevo archivo para rastrear, runhmmer.sh
, y una serie de archivos sin seguimiento (que hemos dejado sin seguimiento por una razón). Ahora podemos “comprometer” estos archivos por etapas a una nueva versión, lo que hace que los archivos escalonados actualizados se almacenen para su posterior referencia. Al comprometernos, necesitamos ingresar un mensaje de compromiso, lo que nos da la oportunidad de resumir los cambios que se están cometiendo.

En este punto, un estado git
se limitaría a informarnos que todavía tenemos archivos sin seguimiento. Supongamos que hacemos algunas ediciones a runhmmer.sh
(agregando una nueva línea de comentarios, quizás), así como creamos un nuevo archivo README.txt
describiendo el proyecto.

Al ejecutar git status
en este punto se reportaría un nuevo archivo sin seguimiento, README.txt
, así como una lectura de línea modificada: runhmmer.sh
para indicar que este archivo ha cambiado desde el último commit. Podríamos seguir editando archivos y trabajando según sea necesario; cuando estemos listos para confirmar los cambios, solo necesitamos organizar los archivos apropiados y ejecutar otro commit.

Cada versión que cometemos se guarda, y podemos ver fácilmente un registro rápido del historial de un proyecto con git log
.

Observe que a cada commit se le da un número de serie largo, como ec46950b36...
. Para ver las diferencias entre dos commits, podemos ejecutar git diff
con solo los pocos caracteres de cada número de serie, como en git diff 50c11fe ec4695
. El formato de salida no es notablemente legible por defecto.

Muchas otras operaciones pueden ser realizadas por git
, como ver el contenido de archivos de versiones anteriores y “revertir” un proyecto a un estado anterior (al menos para aquellos archivos que son rastreados).
Hay otras dos características dignas de mención. Primero, no es raro tener muchos archivos que nos gustaría dejar sin seguimiento, pero agregar todo el resto uno a la vez con git add
es tedioso. Afortunadamente, git add -A
mira el contenido del archivo .gitignore
(que puede ser necesario crear): cualquier archivo o directorio listado en .gitignore
no será escenificado por git add -A
. (Y se puede rastrear el archivo.gitignore
).
Segundo, el sistema git
hace que sea relativamente fácil compartir proyectos en línea con otros, al crear repositorios en sitios como GitHub. Después de configurar una cuenta en http://github.com (o en un sitio similar, como http://bitbucket.com), puede “empujar” el estado actual de su proyecto desde la línea de comandos a la web. (Los commits futuros también se pueden empujar a medida que los creas). Otros usuarios pueden entonces “clonar” el proyecto desde el sitio web usando el comando git clone
discutido brevemente en el capítulo 6. GitHub y sitios web similares cuentan con excelentes tutoriales para interactuar sus productos con sus propios repositorios de línea de comandos, si desea usarlos.
Ejercicios
- En el archivo
Pz_CDNAS.fasta
, los ID de secuencia se agrupan de acuerdo con sufijos comunes como_TY
, _ACT
y similares. ¿Qué grupo tiene el mayor número de secuencias y cuántas hay en ese grupo? - Usando las diversas herramientas de línea de comandos, extraiga todas las secuencias compuestas por una sola lectura (
nReads=1
) depz_CDNAS.fasta
a un archivo formateado FASTA llamadoPz_CDNAS_Singles.fasta
. - En el archivo de anotación
Pz.annot.txt
, cada ID de secuencia puede estar asociada con múltiples “números” de ontología génica (GO) (columna 2) y una serie de “términos” diferentes (columna 3). Muchos ID están asociados con múltiples números GO, y no hay nada que impida que un número o término en particular se asocie con múltiples ID.¿Qué número GO está asociado con el mayor número de IDs únicos? ¿Con cuántos ID diferentes está asociado? A continuación, responda las mismas preguntas usando el término GO en lugar del número GO. Para este último, ten en cuenta que los separadores de columna en este archivo son caracteres de tabulación,
\ t
, peroawk
por defecto usa cualquier espacio en blanco, incluyendo los espacios que se encuentran en la columna de términos. En este archivo, sin embargo,isocitrato
no es un término, sinoisocitrato deshidrogenasa (nad+)
lo es.
- A diferencia de otras herramientas,
tr
solo puede leer su entrada desde stdin. - Mientras que las bases de datos binarias como las utilizadas por
sqlite3
y Postgres tienen su lugar (especialmente cuando es necesario unir o buscar tablas grandes), almacenar datos en archivos de texto simples facilita el acceso y la manipulación. Una discusión sobre la sintaxis SQL y las bases de datos relacionales está más allá del alcance de este libro; vea Jay Kreibich's Using SQLite (Sebastopol, CA: O'Reilly Media, Inc., 2010) para una introducción amigable asqlite3
y su sintaxis. - Esto no es del todo cierto: el <n>indicador
-f
parauniq
elimina los primeros<n>campos antes de realizar la comparación.
- Linus Torvalds, quien también inició el proyecto del kernel de Linux, desarrolló el sistema
git
. Al citar a Linus: “Soy un bastardo egotista, y nombro a todos mis proyectos por mí mismo. Primero 'Linux, 'ahora' Git '”. (Aquí “git” se refiere a la jerga británica para una persona “cabeza de cerdo y argumentativa”).