Ya hemos visto que Linux trae embebidos algunos comandos útiles como grep, sort, head o tail. A continuación te mostraré algunas otras herramientas de suma utilidad para el uso cotidiano de Bash.
El nombre awk proviene de las iniciales de sus autores. Es un programa poderosísimo que se utiliza, entre otras cosas, para buscar patrones, procesar texto y extraer información de un archivo. Es sumamente práctico para procesar archivos de tipo csv, o uno cuyo texto esté ordenado en columnas por tabulaciones, o uno cuyas columnas estén separadas por "|", etc.
| Comando | Descripción |
|---|---|
awk -F "," '{print $n}' arch |
(-Fields) Muestra los datos de la columna n del archivo |
awk -F "," '{print $m "sep" $n}' arch |
Muestra los datos de las columnas m y n del archivo, separadas por sep |
awk -F "," -v var=valor '{print var $n}' arch |
(-variable) Permite imprimir el valor de una variable antes de la columna n |
awk -F "," '{op} END {print op}' arch |
Efectúa una operación e imprime el resultado. ATENCIÓN: Recordar que la operación va entre llaves ( { }) y que termina con la palabra END |
awk -F "," '{suma += $n} END {print suma}' arch |
Calcula e imprime la suma de todos los valores de la columna n. No olvidar la palabra END |
awk -F "," '{prom += $n / m} END {print prom}' arch |
Calcula e imprime el promedio de la columna n que tiene un total de m valores. No olvidar la palabra END |
awk -F "," 'cond {print cond}' arch |
Evalúa una condición e imprime el resultado |
NOTA: Para archivos CSV u otros cuyas columnas estén divididas por otro separador, siempre es necesario especificar la opción-F. Además, el separador puede escribirse entre comillas dobles (") o simples ('), pero la expresión va exclusivamente entre comillas simples.
Supongamos que tenemos el archivo alumnos.csv:
Isabel,9 años,8,Matemática Joaquín,7 años,5,Historia Kevin,8 años,9,Lengua Laura,10 años,7,Geografía
Veamos cómo se aplica cada comando:
awk -F "," '{print $1}' alumnos.csv
# Isabel
# Joaquín
# Kevin
# Laura
awk -F "," '{print $1 " => " $2}' alumnos.csv
# Isabel => 9 años
# Joaquín => 7 años
# Kevin => 8 años
# Laura => 10 años
awk -F "," -v mat=" se destaca en " '{print $1 mat $4}' alumnos.csv
# Isabel se destaca en Matemática
# Joaquín se destaca en Historia
# Kevin se destaca en Lengua
# Laura se destaca en Geografía
awk -F "," '{suma += $2} END {print "La suma de todas las edades es " suma}' alumnos.csv
# La suma de todas las edades es 34
awk -F "," '{prom += $3 / 4} END {print "El promedio de calificaciones es " prom}' alumnos.csv
# El promedio de calificaciones es 7.25
awk -F "," '$3 >= 7 {print $1 ": " $3}' alumnos.csv # Imprimir las calificaciones mayores o iguales a 7
# Isabel: 8
# Kevin: 9
# Laura: 7
Ahora veamos el caso de un archivo de texto con tabulaciones, por ejemplo frutas.txt:
Mariana manzanas 8 Nicolás naranjas 13 Octavio bananas 10 Pablo duraznos 5 Rogelio peras 9
Como hay tabulaciones, no es necesario especificar -F:
awk '{print $2}' frutas.txt
# manzanas
# naranjas
# bananas
# duraznos
# peras
awk '{print $2 " = " $3}' frutas.txt
# manzanas = 8
# naranjas = 13
# bananas = 10
# duraznos = 5
# peras = 9
awk -v var=" tiene " '{print $1 var $3 " " $2}' frutas.txt
# Mariana tiene 8 manzanas
# Nicolás tiene 13 naranjas
# Octavio tiene 10 bananas
# Pablo tiene 5 duraznos
# Rogelio tiene 9 peras
awk '{suma += $3} END {print "Hay " suma " frutas en total"}' frutas.txt
# Hay 45 frutas en total
awk '{prom += $3 / 5} END {print "En promedio hay " prom " frutas"}' frutas.txt
# En promedio hay 9 frutas
awk '$3 > 10 {print $1 " tiene más de 10" $1}' frutas.txt
# Nicolás tiene más de 10
Como se dijo en un capítulo anterior, awk se puede incorporar a nuestros scripts para realizar cálculos con números decimales. Es un procedimiento muy sencillo, usando la palabra BEGIN:
awk 'BEGIN {print 1.95 + 3.76}' # 5.71
Otra enorme ventaja de awk es que cuenta con ciertas funciones para cálculos más complejos:
sqrt(x) - Raíz cuadrada.
awk 'BEGIN {print sqrt(81)}' # 9
sin(x), cos(x) - Seno y coseno.
awk 'BEGIN {print sin(8.43)}' # 0.838638
awk 'BEGIN {print cos(507)}' # -0.359016
log(x) - Logaritmo natural.
awk 'BEGIN {print log(29.11)}' # 3.37108
Además, si el resultado tiene muchos decimales podemos redondearlo con printf y el operador %.nf, donde n indica la cantidad de dígitos decimales:
awk 'BEGIN {printf "%.3f\n", 1 / 3}' # 0.333
# \n es opcional y sólo produce un salto de línea
Con la opción -v podemos utilizar variables de nuestro código dentro de las expresiones de awk:
iva=0.21
precio=349.50
awk -v p=$precio -v i=$iva 'BEGIN {print "El total es", p + (p * i)}' # El total es 422.895
verduras.txt con este código
albahaca | 14 | $ 10.75 lechuga | 2 | $ 6.00 tomate | 7 | $ 9.50 zanahoria | 6 | $ 7.25 cebolla | 8 | $ 5.00y seleccionar sólo aquellas que tengan igual o más de 6 unidades, imprimiendo su nombre y cantidad.
cut es otro programa que se utiliza para dividir el contenido de un archivo. Si bien no es tan poderoso como awk, es más fácil de usar porque su sintaxis es más sencilla:
cut -f col1,col2... -d sep arch
La opción -f (-fields) indica cuáles son las columnas que se quieren mostrar y la opción -d cuál es el separador (por defecto se considera la tabulación, pero puede ser cualquiera).
Veamos cómo funciona empleando nuevamente el archivo alumnos.csv:
cut -f 1,3 -d "," alumnos.csv # Isabel,8 # Joaquín,5 # Kevin,9 # Laura,7
NOTA: Como se puede apreciar, se imprime también el separador original del archivo, ya sea una coma, una tabulación, etc.
verduras.txt del ejercicio anterior, mostrar solamente las columnas del nombre y del precio.frutas.txt anterior, ejecuta la instrucción cut -f 2 frutas.txt. Explica el resultado y corrije el archivo para que se muestren correctamente las columnas de los nombres y las frutas.En Linux existe el programa cron (Command Run ON) que permite ejecutar tareas preprogramadas automáticamente cada cierto intervalo de tiempo. Estas automatizaciones se agrupan en una tabla llamada crontab, donde se detalla en cada línea una tarea distinta. Cada usuario puede tener su propia crontab o bien puede existir una a nivel global de sistema.
| Comando | Descripción |
|---|---|
crontab -l |
(-list) Muestra un listado de las tareas programadas |
crontab -e |
(-edit) Abre el editor de texto para poder administrar las tareas [1] |
crontab -r |
(-remove) Elimina la crontab actual |
[1] La primera vez que se ejecute Cron pedirá elegir el editor que se usará por defecto. Por supuesto, éste se puede cambiar luego.
La sintaxis es simple: 5 asteriscos separados por espacios (* * * * *) y el nombre del comando o del script a ejecutarse:
* * * * * comando
NOTA: Si lo que se va a ejecutar es un script, se debe escribir su ruta absoluta.
Cada uno de los asteriscos indica una unidad de tiempo. De izquierda a derecha:
0 - 59)0 - 23)1 - 31)1 - 12)0 - 6), donde 0 = domingoEjemplos:
45 9 * * 3 # Se ejecuta todos los miércoles a las 9:45 0 19 10 * * # Se ejecuta todos los 10 de cada mes a las 19:00 30 22 17 11 * # Se ejecuta cada 17 de noviembre a las 22:30
NOTA: Es recomendable probar primero de modo manual el comando para verificar que funciona adecuadamente.
En Crontab también se utilizan comodines:
| Comodín | Indica |
|---|---|
* |
Cualquier valor |
, |
Más de un valor |
- |
Rango |
*/ |
Frecuencia |
Algunos ejemplos:
* * * * * # Se ejecutará cada minuto 0 7,13,18 * * * # Se ejecutará a las 7, a las 13 y a las 18 0 8-12 * * * # Se ejecutará cada hora entre las 8 y 12 inclusive */15 * * * * # Se ejecutará cada 15 minutos
¡Hola, mundo!" en un archivo llamado saludo.txt y establecer con Cron que se ejecute cada 5 minutos. (Pista: utilizar el operador >>).Ya pasó media hora" y se ejecute a la hora y cuarto (15 min) y menos cuarto (45 min), por las pŕoximas 2 horas.Son las [hora] horas" y que efectivamente se ejecute en punto en las próximas 3 horas. (Pista: utilizar el comando date +%H:%M)sed (stream editor) es un programa múy útil para modificar el texto de un archivo.
| Comando | Descripción |
|---|---|
sed 's/str1/str2/g' arch |
Sustituye todas las coincidencias de str1 por str2 (la s indica "sustitución" y la g indica "global"), sin alterar el archivo original |
sed -i 's/str1/str2/g' arch |
(-in-place) Sustituye todas las coincidencias de str1 por str2, modificando el archivo original |
sed -n 's/str1/str2/p' arch |
Sustituye todas las coincidencias de str1 por str2, imprimiendo únicamente aquellas líneas en las que aparece |
sed -r 's/regex/str/g' arch |
(-regular-expression) Permite utilizar expresiones regulares (RegEx) |
sed 's/^/pref/' arch |
Añade un prefijo al comienzo de cada línea |
Veamos algunos ejemplos de cómo se aplica sed. Supongamos que tenemos un archivo de texto llamado prueba.txt con el siguiente contenido:
¡Hola, mundo! Esta es la línea 2 y esta es la línea 3. ¡Bienvenido al mundo de Bash!
Entonces:
sed 's/mundo/universo/g' prueba.txt # ¡Hola, universo! # Esta es la línea 2 # y esta es la línea 3. # ¡Bienvenido al universo de Bash!
sed -i 's/línea/fila/g' prueba.txt # SÍ se modifica el archivo original # ¡Hola, mundo! # Esta es la fila 2 # y esta es la fila 3. # ¡Bienvenido al mundo de Bash! cat prueba.txt # ¡Hola, mundo! # Esta es la fila 2 # y esta es la fila 3. # ¡Bienvenido al mundo de Bash!
sed -n 's/mundo/universo/p' prueba.txt # ¡Hola, universo! # ¡Bienvenido al universo de Bash!
sed -r 's/la línea [2,3]/otra línea/g' prueba.txt # Sustituye "la línea 2" y "la línea 3" por "otra línea" # ¡Hola, mundo! # Esta es otra línea # y esta es otra línea. # ¡Bienvenido al mundo de Bash!
sed 's/^/=> /' prueba.txt # => ¡Hola, mundo! # => Esta es la línea 2 # => y esta es la línea 3. # => ¡Bienvenido al mundo de Bash!
prueba.txt, sustituir "a es la línea" por "e es el renglón", modificando el archivo original.--> " (espacio incluido).o" por "0" (ceros).a" y "e" por "4".El programa tee es muy sencillo: permite guardar el resultado de un comando, al mismo tiempo que lo imprime en pantalla. Cabe remarcar que siempre debe utilizarse en un pipe a la salida de otro comando. Por ejemplo, supongamos que tenemos estos archivos y directorios:
Imágenes Música Videos script1.sh script2.sh script3.sh script4.sh
Y queremos guardar en un archivo de texto un listado con los archivos de scripts únicamente:
ls *.sh | tee scripts.txt
Entonces el siguiente listado se mostrará por consola y se guardará en el archivo scripts.txt:
script1.sh script2.sh script3.sh script4.sh
jpg.tr es un comando que se usa para convertir, reemplazar o borrar caracteres en un archivo. Al igual que tee, debe incluirse como parte de un pipe o bien con el operador < arch (¿recuerdas qué es lo que hace?)
Ejemplos:
echo "¡hola, mundo!" | tr a-z A-Z # ¡HOLA, MUNDO! tr a-z A-Z < archivo # Convierte todo el texto del archivo a mayúsculas
Es importante mencionar que el comando tr NO modifica el archivo original, entonces para guardar el resultado podemos simplemente utilizar el operador >.
tr ... < orig > nuevo
| Comando | Descripción |
|---|---|
tr char1 char2 |
Reemplaza char1 por char2 |
tr char1-char2 char3-char4 |
Reemplaza el rango entre char1 y char2 por el rango entre char3 y char4 |
tr char1,char2 char3,char4 |
Reemplaza los caracteres char1 y char2 por char3 y char4 respectivamente |
tr [:lower:] [:upper:]tr a-z A-Z |
Convierte las letras minúsculas a mayúsculas. También se puede aplicar al revés |
tr [:space:] char |
Sustituye los espacios por un caracter |
tr [:digit:] char |
Sustituye los dígitos por un caracter |
tr -d char |
(-delete) Borra el o los caracteres indicados |
tr -c char1 char2 |
(-complement) Reemplaza con char2 a todos aquellos caracteres que NO sean char1 |
tr -s char |
(-squeeze-repeats) Reduce una secuencia de caracteres repetidos a uno solo (por ejemplo, cuando hay muchos espacios). |
tr -s char1 char2 |
Reduce una secuencia de caracteres repetidos a uno solo, y lo sustituye por char2 |
Veamos cada uno en detalle:
echo "aprendiendo en bash" | tr [:lower:] [:upper:] # APRENDIENDO EN BASH
echo "aprendiendo en bash" | tr b-e X # aprXnXiXnXo Xn Xash
echo "aprendiendo en bash" | tr d,e % # apr%n%i%n%o %n bash
echo "aprendiendo en bash" | tr [:space:] - # aprendiendo-en-bash
echo "4pr3nd13nd0 3n b4sh" | tr [:digit:] . # .pr.nd..nd. .n b.sh
echo "aprendiendo en bash" | tr -d en # aprdido bash
echo "aprendiendo en bash" | tr -c en + # +++en++en+++en++++++
NOTA: El último caracter reemplazado corresponde a \n (salto de línea).
echo "aprendiendo en bash" | tr -s ' ' # aprendiendo en bash
echo "aprendiendo en bash" | tr -s [:space:] _ # aprendiendo_en_bash
Vamos a trabajar sobre un archivo llamado deportes.txt con este código:
0- fútbol 1- atletismo 2- ciclismo 3- tenis 4- básquetbol 5- hockey 6- vóleibol 7- natación 8- rugby 9- karate
)".?". ¿Qué es lo que ocurre y por qué?o" por ceros, las "l" por "1" y las "a" por "4", y guardarlo en un archivo nuevo.k" e "y".i" por puntos (".")n-r por "_".uuidgen es un generador de UUIDs. Un UUID (Universal Unique ID) es una cadena de 32 dígitos hexadecimales (dígitos del 0 al 9 y letras de la "a" a la "f"), dividida por guiones en grupos de 8-4-4-4-12 caracteres. Es un identificador único y prácticamente imposible de duplicar, muy utilizado actualmente.
uuidgen # b299e844-30a9-4533-aecf-88b87b79cc98
tr, generar un UUID con letras en mayúsculas.tr nuevamente, sustituir las letras por los números del 0 al 6.tr para generar un UUID sin guiones.El nombre xargs proviene de extended arguments (argumentos extendidos) y es una herramienta que permite aplicar un comando a cada elemento de una lista. También necesita estar dentro de un pipe y combinarse con otros comandos. Es muy provechoso agregarle la opción -t para mostrar cuál es el comando que está ejecutando.
Algunas aplicaciones prácticas de xargs:
ls *.pdf | xargs -t rm # Elimina los archivos pdf
ls *.sh | xargs -t chmod +r # Permite la lectura de los archivos sh
echo arch1 arch2 | xargs -t touch # Crea dos archivos
find -name "*.txt" | xargs -t grep "Linux" # Busca todos los archivos de texto que contengan la palabra "Linux"
basename -s .jpg -a *.jpg | xargs -t -n1 -i mv {}.jpg {}.bmp # Cambia la extesión de los archivos .jpg a .bmp
Bueno, esto último es un poco complejo y merece una explicación: en la primera parte, basename -s quita la extensión del archivo y -a selecciona todos los archivos con esa extensión; esto da como resultado todos los archivos pero SIN la extensión. En la segunda parte, -n1 indica que el próximo comando se aplicará a cada uno de los archivos; -i indica que se hará un reemplazo de cadena de texto, es decir, que la salida del pipe (cada nombre de archivo) está representado por {}. Y finalmente, con mv se produce el cambio de extensión, manteniendo el nombre original del archivo.
pdf. (Pista: usar el sufijo {1..4}).docx.