{"id":274,"date":"2023-08-31T13:46:03","date_gmt":"2023-08-31T11:46:03","guid":{"rendered":"http:\/\/eines-informatiques.recursos.uoc.edu\/introduccion-a-los-entornos-de-trabajo-gnu-linux\/?page_id=274"},"modified":"2025-03-07T17:52:23","modified_gmt":"2025-03-07T15:52:23","slug":"1-13-3-sintesis-condensada-de-gawk","status":"publish","type":"page","link":"http:\/\/eines-informatiques.recursos.uoc.edu\/introduccion-a-los-entornos-de-trabajo-gnu-linux\/es\/1-13-3-sintesis-condensada-de-gawk\/","title":{"rendered":"1.13.3. S\u00edntesis condensada de GAWK"},"content":{"rendered":"<p>GAWK no se limita a ser una herramienta de filtrado de texto estructurado; es un lenguaje de programaci\u00f3n completo que cuenta con estructuras de control de flujo, bucles, diversos operadores y funciones integradas para trabajar tanto con cadenas de caracteres como con n\u00fameros. Adem\u00e1s, te brinda la posibilidad de controlar el formato de la salida impresa, utilizar estructuras de datos y escribir funciones <em>ad hoc<\/em>. La combinaci\u00f3n inteligente de estos elementos te permitir\u00e1 crear programas para realizar transformaciones complejas en archivos de texto, como podr\u00e1s ver en muchos de los ejemplos que se presentan a continuaci\u00f3n.<\/p>\n<p>La siguiente lista presenta algunos de los elementos y estructuras sint\u00e1cticas esenciales del lenguaje de programaci\u00f3n <code>gawk<\/code>. Aunque no vamos a cubrir todos estos elementos en profundidad, esta lista te dar\u00e1 una idea del poder y la flexibilidad de <code>gawk<\/code> como lenguaje de programaci\u00f3n.<\/p>\n<ul>\n<li><strong>condicionales<\/strong><\/li>\n<\/ul>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\" data-enlighter-theme=\"droide\">if(condicion1){code1}else\r\n\r\nif(condici\u00f3n2){code2}else\r\n\r\n{code3}<\/pre>\n<ul>\n<li><strong>bucles <em>for<\/em> <\/strong><\/li>\n<\/ul>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\" data-enlighter-theme=\"droide\">for (i in array) {code};\u00a0\r\n\r\n\r\nfor (initialization;condition;\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 increment|decrement)<\/pre>\n<ul>\n<li><strong>bucles <em>while<\/em><\/strong><\/li>\n<\/ul>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\" data-enlighter-theme=\"droide\">while(true){code}<\/pre>\n<ul>\n<li><strong>operadores aritm\u00e9ticos<\/strong><\/li>\n<\/ul>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\" data-enlighter-theme=\"droide\">+, -, *, \/, %, =, ++, \u2013, +=, -=, \u2026)<\/pre>\n<ul>\n<li><strong>operadores boleanos<\/strong><\/li>\n<\/ul>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\" data-enlighter-theme=\"droide\">||, &amp;&amp;<\/pre>\n<ul>\n<li><strong>operadores relacionales<\/strong><\/li>\n<\/ul>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\" data-enlighter-theme=\"droide\">>&lt;, &lt;=, ==, !=,&gt;=, &gt;<\/pre>\n<ul>\n<li><strong>funciones integradas<\/strong><\/li>\n<\/ul>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\" data-enlighter-theme=\"droide\">length(str); int(num); index (str1, str2); split(str,arr,del); substr(str,pos,len); printf(fmt,args); tolower(str); toupper(str); gsub(regexp, replacement [, target])<\/pre>\n<ul>\n<li><strong>funciones escritas por el usuario<\/strong><\/li>\n<\/ul>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\" data-enlighter-theme=\"droide\">function FUNNAME (arg1, arg1) {code}<\/pre>\n<ul>\n<li><strong>estructuras de datos<\/strong><\/li>\n<\/ul>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\" data-enlighter-theme=\"droide\">(hashes o\u00a0arreglos\u00a0asociativos):\u00a0array[string]=value<\/pre>\n<p>Evaluemos el potencial de <code>gawk<\/code>. Los conjuntos de datos gen\u00f3micos a menudo se distribuyen con archivos separados para cada cromosoma, y generalmente necesitamos efectuar la misma operaci\u00f3n en cada uno. Para realizar esta tarea, podemos usar la estructura de bucle <em>for <\/em>del<em> shell<\/em>. Si tuvi\u00e9ramos archivos llamados <code>data_chr[chromosome].txt<\/code>, donde [chromosome] var\u00eda de 1 a 22, y quisi\u00e9ramos ejecutar .\/command en ellos, se escribir\u00edan los siguientes comandos en el terminal:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"mowtwo\">$ for i in {1..22}; do .\/command data_chr$i.txt; done<\/pre>\n<p>El c\u00f3digo anterior recorre todos los valores entre 1 y 22, estableciendo la variable de <code>shell<\/code> $i en cada valor, sucesivamente. La sintaxis para especificar los rangos de n\u00fameros es que <code>{A..B}<\/code> da un rango entre <em>A<\/em> y <em>B<\/em>, donde <em>A<\/em> y <em>B<\/em> son valores enteros.<\/p>\n<p>Tambi\u00e9n podemos utilizar <code>for<\/code> para recorrer las extensiones de archivo. Supongamos que ten\u00edamos algunos datos en formato PLINK llamados <code>data.bed, data.bim<\/code> y <code>data.fam<\/code>. Podr\u00edamos listar estos archivos individualmente ejecutando:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"mowtwo\">$ for ext in bed bim fam; do ls data.$ext; done<\/pre>\n<p>Aqu\u00ed, la variable <code>$ext<\/code> (para extensi\u00f3n) se establece sucesivamente en <em>bed<\/em>, <em>bim <\/em>y <em>fam<\/em>. Este ejemplo en particular no es muy \u00fatil, ya que podr\u00edamos haber escrito <code>ls data.*<\/code> y visto que existen estos tres archivos. Lo \u00fatil es poder renombrar el conjunto de datos base con una sola l\u00ednea de c\u00f3digo en el <em>shell<\/em>. Si quisiera renombrar estos archivos <code>human_data.bed, human_data.bim<\/code> y <code>human_data.fam<\/code>, se podr\u00eda escribir:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"mowtwo\">$ for ext in bed bim fam; do mv -i data.$ext human_data.$ext; done<\/pre>\n<p>Otra construcci\u00f3n <code>for<\/code> \u00fatil es recorrer grupos de archivos. Podemos hacer lo siguiente para ejecutar <code>.\/command<\/code> en cada archivo con extensi\u00f3n .txt en nuestro directorio actual:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"mowtwo\">$ for file in *.txt; do .\/command $file; done<\/pre>\n<p>Ahora, supongamos que tenemos un archivo llamado <em>data.txt<\/em> y que queremos separar la informaci\u00f3n correspondiente a cada cromosoma en archivos separados. Podr\u00edamos usar un bucle <em>for<\/em> para recorrer cada n\u00famero de cromosoma y luego una expresi\u00f3n booleana en <code>gawk<\/code> para extraer solo las l\u00edneas correspondientes a ese cromosoma. Comencemos nuestra tarea con un programa que no funciona del todo y luego lo arreglaremos.<\/p>\n<p>Si la columna 2 de <em>data.txt<\/em> contiene los n\u00fameros de cromosoma y queremos archivos separados para cada cromosoma, podr\u00edamos pensar que lo siguiente funciona (ten en cuenta, nuevamente, el comportamiento predeterminado de <code>gawk<\/code> para imprimir las l\u00edneas que coinciden con la expresi\u00f3n booleana dada):<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"mowtwo\">$ for chr in {1..22}; do awk '$2 == $chr' data.txt &gt; data_chr$chr.txt; done<\/pre>\n<p>Esto es casi correcto, pero la expresi\u00f3n dada en <code>gawk<\/code> es\u00a0<code>'$2 == $chr'\u00a0gawk<\/code> no la entiende, porque no conoce ni sabe nada sobre la variable de <em>shell<\/em> <code>$chr<\/code> que se ha definido. En lugar de hacer referencia a una variable en la <em>shell<\/em>, podemos asignar expl\u00edcitamente variables para que <code>gawk<\/code> las use con la opci\u00f3n -v:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"mowtwo\">$ for chr in {1..22}; do awk -v chr=$chr '$2 == chr' data.txt &gt; data_chr$chr.txt; done<\/pre>\n<p>\u00a1No est\u00e1 mal! Podemos proporcionar a <code>gawk<\/code> tantas opciones -v como queramos para todas las variables que nos importen asignar:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"mowtwo\">$ for chr in {1..22};\r\n \u00a0 do awk -v chr=$chr -v threshold=10 '$2 == chr &amp;&amp; $4 &gt; threshold' data.txt\r\n\r\n\u00a0\u00a0 &gt; data_chr$chr.txt; done<\/pre>\n<p>Esto separa cada cromosoma en un archivo individual con la condici\u00f3n de que los valores en la columna 4 sean mayores que 10.<\/p>\n<p>\u00bfQu\u00e9 ocurre si tenemos un archivo que contiene dos columnas con un recuento de \u00ab\u00e9xitos\u00bb y \u00abintentos\u00bb para alg\u00fan proceso, cada uno recolectado de una fuente diferente, y queremos calcular la tasa promedio de \u00e9xito entre todas las fuentes? Podemos usar <code>gawk<\/code> para sumar cada columna y luego imprimir el promedio al final usando una sintaxis especial. Si el archivo <em>data.txt<\/em> tiene los \u00e9xitos y los intentos en las columnas 2 y 3, respectivamente, podr\u00edamos hacer esto:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"mowtwo\">$ gawk 'BEGIN\r\n {total_success = total_attempts = 0;}\r\n\r\n\u00a0{total_success += $2; total_attempts += $3}\r\n\r\nEND\r\n\r\n{print \"\u00c9xitos:\", total_success, \"Intentos:\", total_attempts, \"Tasa:\", total_success \/ total_attempts}' data.txt<\/pre>\n<p>El comando <code>gawk<\/code> ejecuta el c\u00f3digo en la secci\u00f3n BEGIN antes de procesar cualquier l\u00ednea en la entrada y el c\u00f3digo en la secci\u00f3n END despu\u00e9s de leer la entrada. La secci\u00f3n BEGIN inicializa dos variables a 0, la secci\u00f3n de c\u00f3digo principal suma las columnas en cada l\u00ednea, y la secci\u00f3n END imprime los totales y la tasa.<\/p>\n<p>Supongamos ahora que queremos buscar mediante condicionales aquellos ensambles que contiene el organismo en <em>Xenopus tropicalis<\/em>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"mowtwo\">$ gawk ' BEGIN {\r\n \u00a0\u00a0 FS=\"\\t\";\r\n\r\n\u00a0\u00a0\u00a0 print \"assembly_accession\\torganism_name\\tseq_rel_date\\tasm_name\\tsubmitter\"\r\n\r\n\u00a0\u00a0\u00a0 }\r\n\r\n\r\n\r\n{\r\n\r\n\u00a0\u00a0\u00a0 if ($2 == \"Xenopus tropicalis\") {\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 print $1 \"\\t\" $2 \"\\t\" $3 \"\\t\" $4 \"\\t\" $5\r\n\r\n\u00a0\u00a0\u00a0 }\r\n\r\n}\r\n\r\n' ensamble.txt<\/pre>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\" data-enlighter-theme=\"droide\">GCA_017527675.1 Phaeodactylum tricornutum\u00a0 2022-03-24 Phatr3.0\u00a0\u00a0 NCBI\r\n\r\nGCA_011586775.1 Xenopus tropicalis\u00a0\u00a0 2022-04-11 Xenbase_v9.2\u00a0\u00a0\u00a0 NCBI<\/pre>\n<p>En el siguiente ejemplo, se quieren filtrar los datos de Xenopus tropicalis que tengan una fecha de lanzamiento inferior a 2015. El ejemplo utilizar\u00e1 un condicional en <em>bash<\/em> y se crear\u00e1 <em>script<\/em> que se pueda ejecutar. Salva las pr\u00f3ximas \u00f3rdenes en un fichero de tu terminal.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\" data-enlighter-theme=\"droide\">#!\/bin\/bash<\/pre>\n<p># Leer la tabla y guardar las l\u00edneas que cumplen las condiciones en un nuevo archivo<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\" data-enlighter-theme=\"droide\">awk -F'\\t' 'NR==1 || ($2 == \"Xenopus tropicalis\" &amp;&amp; $3 &gt; \"2015-01-01\")' $1 &gt; filtered_table.txt<\/pre>\n<p># Contar el n\u00famero de l\u00edneas en el archivo filtrado<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\" data-enlighter-theme=\"droide\">num_lines=$(wc -l &lt; filtered_table.txt)<\/pre>\n<p># Si el n\u00famero de l\u00edneas es mayor que 1 (es decir, si hay entradas que cumplen las condiciones),<\/p>\n<p># imprimir un mensaje y el contenido del archivo filtrado<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\" data-enlighter-theme=\"droide\">if [ $num_lines -gt 1 ]; then\r\n\r\n\u00a0 echo \"Se encontraron las siguientes entradas para Xenopus tropicalis publicadas despu\u00e9s de 2015-01-01:\"\r\n\r\n\u00a0 cat filtered_table.txt\r\n\r\n# Si el n\u00famero de l\u00edneas es igual a 1, imprimir un mensaje con el nombre de la entrada\r\n\r\nelif [ $num_lines -eq 1 ]; then\r\n\r\n\u00a0 echo \"Se encontr\u00f3 la siguiente entrada para Xenopus tropicalis publicada despu\u00e9s de 2015-01-01:\"\r\n\r\n\u00a0 awk -F'\\t' '{print $4}' filtered_table.txt<\/pre>\n<p># Si el n\u00famero de l\u00edneas es 0, imprimir un mensaje de que no se encontraron entradas que cumplan las condiciones<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\" data-enlighter-theme=\"droide\">else\r\n\r\n\u00a0 echo \"No se encontraron entradas para Xenopus tropicalis publicadas despu\u00e9s de 2015-01-01.\"\r\n\r\nfi<\/pre>\n<p>Salva el fichero y ejecuta las siguientes \u00f3rdenes en el terminal:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"mowtwo\">\u00a0\u00a0\u00a0\u00a0 $ chmod +x script.sh<\/pre>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"mowtwo\"> \u00a0\u00a0\u00a0 $ .\/script.sh ensamble.txt\r\n<\/pre>\n<p>Este <em>script<\/em> emplea <code>gawk<\/code> para leer la tabla y guardar las l\u00edneas que cumplen las condiciones en un nuevo archivo llamado <em>filtered_table.txt.<\/em> Luego, cuenta el n\u00famero de l\u00edneas en ese archivo y utiliza dos condiciones <em>if<\/em> para imprimir mensajes diferentes dependiendo de si hay entradas que cumplan las condiciones o no. En el primer caso, cuando hay m\u00e1s de una entrada que cumple las condiciones, el <em>script<\/em> imprime un mensaje que indica que se encontraron entradas y muestra el contenido de la tabla filtrada. En el segundo caso, imprime un mensaje si solo hay una entrada que cumple la condici\u00f3n y la \u00faltima acci\u00f3n ocurrir\u00e1 si no hay ninguna entrada en el fichero de partida que cumpla las condiciones demandadas.<\/p>\n<p>La tabla 12 es un listado de las operaciones m\u00e1s comunes y usadas con GAWK.<\/p>\n<div class=\"tabletitle\"><p>Tabla 12. Operaciones utilizadas en GAWK.<\/p>\n<\/div>\n<table width=\"602\">\n<tbody>\n<tr class=\"table-header\">\n<td width=\"123\"><strong>Variable<\/strong><\/td>\n<td width=\"480\"><strong>Descripci\u00f3n<\/strong><\/td>\n<\/tr>\n<tr>\n<td width=\"123\"><code>i=0<\/code><\/td>\n<td width=\"480\">Asignar un valor<\/td>\n<\/tr>\n<tr>\n<td width=\"123\"><code>a[i]=0;<\/code><\/td>\n<td width=\"480\">Guardar un valor en una tabla<\/td>\n<\/tr>\n<tr>\n<td width=\"123\"><code>i++;<\/code><\/td>\n<td width=\"480\">Incrementar un contador<\/td>\n<\/tr>\n<tr>\n<td width=\"123\"><code>print i;<\/code><\/td>\n<td width=\"480\">Mostrar una variable por pantalla<\/td>\n<\/tr>\n<tr>\n<td width=\"123\"><code>print NR<\/code><\/td>\n<td width=\"480\">Mostrar el n\u00famero de l\u00edneas procesadas<\/td>\n<\/tr>\n<tr>\n<td width=\"123\"><code>print $1,$4<\/code><\/td>\n<td width=\"480\">Mostrar la primera y cuarta columnas<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"tablefooter\"><p>Fuente: elaboraci\u00f3n propia.<\/p>\n<\/div>\n<p>Y en la tabla 13 se muestran ejemplos de instrucciones condicionales con GAWK.<\/p>\n<div class=\"tabletitle\"><p>Tabla 13. Instrucciones condicionales con GAWK.<\/p>\n<\/div>\n<table width=\"602\">\n<tbody>\n<tr class=\"table-header\">\n<td width=\"246\"><strong>Variable<\/strong><\/td>\n<td width=\"357\"><strong>Descripci\u00f3n<\/strong><\/td>\n<\/tr>\n<tr>\n<td width=\"246\"><code>if ($1 &gt; 0) print $0;\u00a0<\/code><\/td>\n<td width=\"357\">Si la primera es positiva<\/td>\n<\/tr>\n<tr>\n<td width=\"246\"><code>if ($1 &lt; 0) print $0;\u00a0<\/code><\/td>\n<td width=\"357\">Si la primera es negativa<\/td>\n<\/tr>\n<tr>\n<td width=\"246\"><code>if ($1 &gt;= 0) print $0;\u00a0<\/code><\/td>\n<td width=\"357\">Si la primera columna es mayor o igual a cero<\/td>\n<\/tr>\n<tr>\n<td width=\"246\"><code>if ($1 &lt;= 0) print $0;\u00a0<\/code><\/td>\n<td width=\"357\">Si la primera columna es menor o igual a cero<\/td>\n<\/tr>\n<tr>\n<td width=\"246\"><code>if ($1 == 0) print $0;\u00a0<\/code><\/td>\n<td width=\"357\">Si la primera columna es igual a cero<\/td>\n<\/tr>\n<tr>\n<td width=\"246\"><code>if (CONDICION1) &amp;&amp; (CONDICION2)<\/code><\/td>\n<td width=\"357\">Si se cumplen las dos condiciones<\/td>\n<\/tr>\n<tr>\n<td width=\"246\"><code>if (CONDICION1) || (CONDICION2<\/code><\/td>\n<td width=\"357\">Si se cumple alguna de las dos condiciones<\/td>\n<\/tr>\n<tr>\n<td width=\"246\"><code>if \u00a1(CONDICION1)<\/code><\/td>\n<td width=\"357\">Si no se cumple la condici\u00f3n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"tablefooter\"><p>Fuente: elaboraci\u00f3n propia.<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>GAWK no se limita a ser una herramienta de filtrado de texto estructurado; es un lenguaje de programaci\u00f3n completo que cuenta con estructuras de control de flujo, bucles, diversos operadores y funciones integradas para trabajar tanto con cadenas de caracteres como con n\u00fameros. Adem\u00e1s, te brinda la posibilidad de controlar el formato de la salida [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":[],"acf":[],"_links":{"self":[{"href":"http:\/\/eines-informatiques.recursos.uoc.edu\/introduccion-a-los-entornos-de-trabajo-gnu-linux\/es\/wp-json\/wp\/v2\/pages\/274"}],"collection":[{"href":"http:\/\/eines-informatiques.recursos.uoc.edu\/introduccion-a-los-entornos-de-trabajo-gnu-linux\/es\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"http:\/\/eines-informatiques.recursos.uoc.edu\/introduccion-a-los-entornos-de-trabajo-gnu-linux\/es\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"http:\/\/eines-informatiques.recursos.uoc.edu\/introduccion-a-los-entornos-de-trabajo-gnu-linux\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/eines-informatiques.recursos.uoc.edu\/introduccion-a-los-entornos-de-trabajo-gnu-linux\/es\/wp-json\/wp\/v2\/comments?post=274"}],"version-history":[{"count":18,"href":"http:\/\/eines-informatiques.recursos.uoc.edu\/introduccion-a-los-entornos-de-trabajo-gnu-linux\/es\/wp-json\/wp\/v2\/pages\/274\/revisions"}],"predecessor-version":[{"id":1312,"href":"http:\/\/eines-informatiques.recursos.uoc.edu\/introduccion-a-los-entornos-de-trabajo-gnu-linux\/es\/wp-json\/wp\/v2\/pages\/274\/revisions\/1312"}],"wp:attachment":[{"href":"http:\/\/eines-informatiques.recursos.uoc.edu\/introduccion-a-los-entornos-de-trabajo-gnu-linux\/es\/wp-json\/wp\/v2\/media?parent=274"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}