El procesamiento en paralelo en Bash se refiere a la ejecución simultánea de múltiples tareas o comandos en un script de Bash. Esto permite aprovechar al máximo los recursos disponibles en un sistema y puede acelerar considerablemente la ejecución de un programa o script.
Hay varias formas de lograr el procesamiento en paralelo en Bash. Una de las formas más comunes es utilizando subprocesos en segundo plano (background processes) y el comando wait para esperar a que todos los subprocesos terminen antes de continuar con el script principal.
Aquí hay un ejemplo simple que muestra cómo ejecutar múltiples comandos en paralelo usando subprocesos en segundo plano,
1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash
# Comando 1 en segundo plano
comando1&
pid1=$!
# Comando 2 en segundo plano
comando2&
pid2=$!
# Esperar a que los subprocesos terminen
wait$pid1
wait$pid2
# Continuar con el script principal
echo"Todos los subprocesos han terminado."
Es importante tener en cuenta que el número de subprocesos en paralelo que se pueden ejecutar al mismo tiempo puede estar limitado por el sistema operativo y los recursos disponibles en el sistema. Además, el procesamiento en paralelo puede introducir complejidad adicional debido a posibles problemas de concurrencia, como la competencia por recursos compartidos. Por lo tanto, es importante diseñar y probar cuidadosamente el uso de procesamiento en paralelo en un script de Bash.
Un ejemplo
Supongamos que tienes una lista de URLs de sitios web y deseas extraer el título de cada página para realizar un análisis posterior. En lugar de procesar cada URL secuencialmente, puedes aprovechar el procesamiento en paralelo para acelerar el proceso. Aquí hay un ejemplo de cómo podrías hacerlo,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/bin/bash
# Lista de URLs
urls=(
"https://www.ejemplo1.com"
"https://www.ejemplo2.com"
"https://www.ejemplo3.com"
# Añadir más URLs según sea necesario
)
# Función para extraer el título de una página web
Por si estás programando algun script en bash o necesitar imprimir algun texto en consola de manera especial y no recuerdas cual era la combinación, El siguiente script (color-bash.sh) te imprime una tabla de colores en bash:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/bin/bash
# prints a color table of 8bg * 8fg * 2 states (regular/bold)
Grep (por sus siglas en inglés Globally Search For Regular Expression and Print out) es una herramienta de líneas de comando usada para buscar cadenas de texto y encontrar coincidencias dentro de este. También puede ser utilizada para encontrar una palabra o combinación de palabras dentro de un fichero.
Esta herramienta requiere de dos parámetros básicos como el patrón a buscar y el archivo en el que se realizará la búsqueda. Además, es importante que conozcamos las expresiones regulares, debido a que estos patrones nos permitirán introducir combinaciones y caracteres para mejorar las búsquedas que hagamos. Una expresión regular usualmente es tomada por el comando de una línea de comandos, lee la lista de archivos e imprime las líneas que contienen coincidencias con la expresión regular.
1
2
3
4
5
6
CLASES DE CARACTERES EN GREP.
[:blank:]Coincide con caracteres en blanco,tales como un espaciooun tabulador.
[:digit:]Coincide con caracteres numéricos.Equivalea[0-9]
[:lower:]Coincide con caracteres alfabéticos en minúscula.Equivalea[a-z]
[:upper:]Coincide con caracteres alfabéticos en mayúsculas.Equivalea[A-Z]
[:punct:]Coincide con signos de puntuacióntales como!,#, $ y @
1.- Podemos filtrar únicamente aquellas líneas que contengan números con el siguiente comando:
grep [[:digit:]] /tmp/archivo.txt
2.- Otra funcionalidad interesante es la de buscar varios patrones en uno o varios archivos. Supongamos que tenemos un archivo de texto denominado /tmp/usuarios.txt, que contiene lo siguiente:
Power
Docker
Y quisiéramos buscar dentro del archivo /etc/group aquellas líneas que
contengan las palabras «power» o «docker». Podríamos hacer lo siguiente:
grep -f /tmp/usuarios.txt /etc/group
3.- Este comando filtra, del archivo /etc/passwd, aquellas líneas que incluyan la palabra «root» o «dbus» al principio de la línea.
grep -E «^root|^dbus» /etc/passwd
4.- Buscar los número con 1 o 2 dígitos…
grep -E «^[0-9][0-9]?$» numeros.txt
Si cambiamos por un * aparecerá 0 veces o más veces por lo tanto mostrara todos los números.
$ grep -E «^[0-9][0-9]*$» numeros.txt
Podemos decir que los primeros números sean del 0 al 9 y los segundos del 0 al 5 por ejemplo. Eso excluirá los 2°, 3° y 4° dígito superior a 5 …
$ grep -E «^[0-9][0-5]*$» numeros.txt
Determinar el número exacto de veces que deseamos que se repita el rango.
$ grep -E «^[0-9]{3}$» numeros.txt
144
233
Especificamos un rango de veces. Por ejemplo los números que contengan 2 a 4 veces.
$ grep -E «^[0-9]{2,4}$» numeros.txt
55
89
144
987
1597
6765
Agrupar expresiones.
Si queremos los números de 1 dígito y los de 3 dígitos, podemos usar dos expresiones regulares dentro de grep con la opción -e por ejemplo…
8.- Sacar 2 lineas por encima y 2 lineas por debajo del output :
Cat /etc/passwd | grep -i “ROOT” -C 2
9.- Si al inicio de la salida del comando quieren añadir el nombre del fichero en que se halla la línea mostrada en pantalla deberán usar la opción -H del siguiente modo:
grep -H -F ‘the’ .bashrc
10.- Pero si queremos obtener únicamente aquellas líneas cuyo único contenido sea la palabra blanco añadiremos la opción -x del siguiente modo:
grep -w -x «blanco» /home/joan/opciones.txt
11.- Con él podemos buscar, por ejemplo, secuencias de varios números seguidos que empiecen con «:».
grep -E ‘:[0-9]+’ regex
12.- Primero vamos a buscar todas las secuencias de cuatro dígitos que haya:
grep ‘[0-9]\{4\}’ regex
13.- Ahora el otro ejemplo con las llaves. Supongamos que queremos encontrar palabras que tengan entre 3 y 6 letras minúsculas. Podríamos hacer lo siguiente:
grep ‘[a-z]\{3,6\}’ regex
14.- Extraer la lista de direcciones de correo electrónico de un archivo:
21.- Cantidad de líneas que comiencen con una o ninguna c seguida de la cadena ati.
grep -cE «^c?ati» /usr/share/hunspell/en_US.dic
22.- Vamos con cosas un poco más complicadas. El carácter «+» empareja con el carácter que aparece a su izquierda repetido al menos una vez. Este carácter sólo está disponible con las expresiones regulares extendidas. Con él podemos buscar, por ejemplo, secuencias de varios números seguidos que empiecen con «:».
grep -E ‘:[0-9]+’ regex
23.- Buscar todas las secuencias de cuatro dígitos que haya:
Para este ejemplo supondremos que tenemos el siguiente archivo en formato JSON (datos.json), y necesitamos extraer los NOMBRES. Esto es solo un ejemplo básico de como se pueden obtener los campos :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
{
"nombre":" Pedro Fernandez",
"edad":30,
"ciudad":"Santiago",
"profesion":"Ingeniero",
"hobbies":["natació "lectura", "senderismo"]
}
{
"nombre": "Gonzalo reiser Ampuero",
"edad": 30,
"ciudad": "Santiago",
"profesion": "Ingeniero",
"hobbies": ["natació"lectura","senderismo"]
}
{
"nombre":"Juan Silva",
"edad":30,
"ciudad":"Santiago",
"profesion":"Ingeniero",
"hobbies":["natació "lectura", "senderismo"]
}
{
"nombre": "Hans petrovic",
"edad": 30,
"ciudad": "Santiago",
"profesion": "Ingeniero",
"hobbies": ["natació"lectura","senderismo"]
}
{
"nombre":"Sebastian Ramirez Fuentes",
"edad":30,
"ciudad":"Santiago",
"profesion":"Ingeniero",
"hobbies":["natació "lectura", "senderismo"]
}
1
Con el siguiente SCRIPTS podemos obtener estos datos:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/bash
# Nombre del archivo JSON
archivo_json="datos.json"
# Campo que queremos extraer
campo="nombre"
# Utilizar grep para buscar el campo en el archivo JSON
Este script básico, para manejar una agenda telefónica. Es un ejemplo que puede servir como base para realizar un SCRIPT más completo. Aquí solo guarda el nombre y número telefónico. Pero queda a la imaginación para darle un uso más profesional.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#!/bin/bash
# Verificar si se proporcionó un argumento (nombre del archivo de la agenda)
if[$# -eq 0 ]; then
echo"Uso: $0 archivo_agenda.txt"
exit1
fi
# Función para añadir un nuevo registro a la agenda
En *nix, el comando ps permite listar y manejar procesos pero no se suele conocer la forma directa de visualizar el tiempo que lleva un proceso en ejecución. En realidad se puede sacar con la salida por defecto a partir del valor de la columna STIME, que indica el momento en el que se inició (START TIME) pero hay que «calcular» el tiempo.
Para calcular el tiempo en ejecución de un proceso podemos utilizar el parámetro etime (elapsed time), el cual muestra en formato de fecha el tiempo que el proceso que le indiquemos lleva ejecutándose:
1
etime-elapsed time since the process was started,inthe form[[dd-]hh:]mm:ss.
Lo combinaremos con otro parámetro (-p pidlist) en el que le diremos el PID a revisar y el formato (-o):
En Bash 4 y versiones posteriores, las matrices asociativas le permiten crear listas de pares clave-valor que se pueden buscar por clave o por valor. Debido a la relación bidireccional entre la clave y el valor, también se denominan diccionarios de datos.
Podemos iterar a través de una matriz asociativa usando un for círculo. Este script es «asociative.sh». Define una matriz asociativa con cuatro entradas, una para cada uno de «perro», «gato», «robin» y «humano». Estas son las claves. Los valores son el número (predeterminado) de patas que tiene cada uno.
El iterador se llama legs . Tenga en cuenta que el encabezado del ciclo contiene un «!«Punto de exclamación. Esto no actúa como el operador lógico NOT, es parte de la sintaxis de matriz asociativa. Se requiere para buscar a través de la matriz.
El cuerpo del bucle realiza una prueba de comparación de cadenas. Si el valor del miembro de la matriz es «de dos patas», imprime el valor de la clave en la ventana del terminal. Cuando lo ejecutamos, el script imprime las criaturas de dos patas.
Este codigo ${animals[@]} se expande a los valores y ${!animal[@]} se expande a dog cat robin human.
Permite la sustitución del contenido de la variable siguiendo una amplia variedad de reglas. Los distintos formatos para la expansión de paráme- tros son :
BASH proporciona unas potentes herramientas para el tratamiento de cadenas, sin embargo la sintaxis puede resultar engorrosa y requiere de experiencia para depurar el código. Por lo tanto, se recomienda crear guiones que resulten fáciles de comprender, documentando claramente las órdenes más complejas. Aqui algunos ejemplos de utilidad :
Realizar una copia en forma recursiva, es decir que debe copiar el directorio y todo su contenido.
1
cp-r/Fotos/respaldo/MisFotos
Si con este mismo ejemplo se requiere respaldar el directorio /Fotos, pero que solo grabe los archivos que se han modificado o no existe en el destino (-u) y además que muestre en pantalla lo que esta realizando.
1
cp-r-u-v/Fotos/respaldo/MisFotos#o también ==>> cp -ruv /Fotos /respaldo/MisFotos
Otra utilidad es para realizar backups, por ejemplo, si constantemente trabajamos con un archivo (planilla.txt) y deseamos tener copias de versiones del mismo.
Aqui copiamos el archivo sobre si mismo, el comando cp por si mismo no lo puede hacer, por eso utilizamos la opcion «-force» con la cula lo forzamos a realizar la copia. Y con la opción «-backup=numbered«, le indicamos que las copias esten numeradas consecutivamente. Estas quedarían como : planilla.txt~1~ planilla.txt~2~ planilla.txt~3~ etc…..
Para conservar la propiedad,permisos y fecha y hora del archivo a copiar, se utiliza la opción «-p» (–preserve)
1
cp-pplanilla.txt planilla2.txt
Preservar enlaces duros mientras se copia. De forma predeterminada, el comando cp no conserva los vínculos físicos entre los archivos al copiar. Sin embargo, puede usar la opción ‘-l’ para crear enlaces duros en lugar de copiar los archivos reales. Esto puede ser útil cuando desea crear un directorio espejo sin usar espacio adicional en el disco.
1
cp-Rl/source_directory/destination_directory/
Copiar archivos sin seguir enlaces simbólicos. Al copiar directorios usando la opción recursiva ( -R ), el comando cp sigue los enlaces simbólicos de forma predeterminada. Para evitar este comportamiento y, en su lugar, copiar los enlaces simbólicos, utilice la opción ‘-P’:
Para un mejor manejo de los colores en SCRIPT BASH se pueden definir como variables de la siguiente forma :
1
2
red='\033[31m'
reset='\033[0m'
Entonces, puedes accionar los colores simplemente con el comando Echo:
1
echo-e"${red}Esto es un texto rojo.${reset}Y ahora el texto vuelve a ser normal."
A continuación resumimos los distintos códigos escape para los diversos colores de fuente y fondo:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
\033[30mColor de fuente negro
\033[31mColor de fuente rojo
\033[32mColor de fuente verde
\033[33mColor de fuente amarillo
\033[34mColor de fuente azul
\033[35mColor de fuente magenta
\033[36mColor de fuente turquesa
\033[37mColor de fuente blanco
\033[40mColor de fondo negro
\033[41mColor de fondo rojo
\033[42mColor de fondo verde
\033[43mColor de fondo amarillo
\033[44mColor de fondo azul
\033[45mColor de fondo magenta
\033[46mColor de fondo turquesa
\033[47mColor de fondo gris
Además del color de la fuente y del fondo, con el comando de Linux Echo también pueden determinarse otras características del texto como la negrita o el subrayado. He aquí los códigos de distintas propiedades de texto:
1
2
3
4
5
\033[0mRestaurar todas las caracteristicas
\033[1mNegrita
\033[4mSubrayado
\033[5mParpadeo
\033[7mPantalla inversa
Si quieres escribir el texto rojo en negrita, utiliza el siguiente código:
1
echo-e"\033[1;31mEsto es un texto rojo en negrita."
Para aplicar una acción u otra en función de una determinada circunstancia tendremos que usar un condicional if. Imaginemos que tenemos un fichero opciones.txt y tiene el siguiente contenido:
1
2
3
blanco
negro
azul
Ahora queremos que si una de las líneas del fichero contiene la palabra blanco la terminal nos de como resultado 1. En el caso que el fichero de texto no disponga de la palabra blanco entonces queremos que nos devuelva 0. Para conseguir nuestro propósito podemos usar el siguiente comando:
Nótese que en este ejemplo usamos grep con la opción -x. La opción -x hace que grep solo considere las líneas cuyo contenido completo sea la palabra blanco.
En el resaltado de color se muestra el contenido definido por nuestra expresión regular. En nuestro caso la expresión regular define 4 cifras entre el 0 y el 9, separadas por puntos. Cada una de las cifras entre el 0 y el 9 está separada puntos y podrá tener 1, 2 o 3 caracteres.
Si queremos que la salida del comando solo muestre las IP omitiendo las palabras localhost y gk55 podemos usar la opción -o. De este modo grep solo mostrará la cadena de texto o palabra de cada una de las líneas que coincide con nuestro criterio de búsqueda. Por lo tanto si ejecutamos el siguiente comando:
En este ejemplo, se utiliza un array asociativo en bash (errores) para contabilizar la cantidad de errores por tipo desde un archivo de log ($archivo_log). El archivo de log se lee línea por línea utilizando un bucle while y el comando read, y luego se utiliza el comando cut para extraer el tipo de error de cada línea, asumiendo que los errores están separados por dos puntos («:») en el archivo de log. Luego, se incrementa la cuenta de errores en el array asociativo utilizando la sintaxis errores["$tipo_error"]++.
Finalmente, se muestra el resultado en la salida, iterando sobre las claves del array asociativo ("${!errores[@]}") y mostrando el tipo de error y la cantidad de errores correspondiente utilizando la sintaxis ${errores[$tipo_error]}.
En este ejemplo, se utiliza el comando rsync para realizar un respaldo incremental del directorio de origen ($directorio_origen) al directorio de destino ($directorio_destino). El respaldo se realiza utilizando las opciones -a para mantener los atributos y permisos, --delete para eliminar archivos en el directorio de destino que ya no existen en el directorio de origen, y --backup para crear copias de seguridad de los archivos modificados o eliminados.
Además, se utiliza la opción --backup-dir para especificar el directorio de destino donde se guardarán las copias de seguridad de los archivos modificados o eliminados, utilizando la fecha actual en el nombre del directorio ($directorio_destino$fecha_actual) para hacer que el respaldo sea incremental.
La información del respaldo se registra en un archivo de registro ($archivo_log) que incluye la fecha del respaldo, los directorios de origen y destino, y el directorio de destino donde se guardaron las copias de seguridad.
echo"Búsqueda de patrones en el archivo de log completada."
En este ejemplo, se definen los patrones a buscar en el archivo de log en el array patrones. Luego, se utiliza un bucle for para iterar sobre cada patrón y se utiliza el comando grep para buscar el patrón en el archivo de log especificado en la variable archivo_log. El uso de la opción -i en el comando grep hace que la búsqueda sea insensible a mayúsculas y minúsculas.
Puedes agregar o modificar los patrones en el array patrones según tus necesidades. Al ejecutar este script, mostrará las líneas del archivo de log que contienen los patrones buscados, con un separador «—» para cada patrón encontrado.
Ten en cuenta que este es solo un ejemplo básico y que puedes personalizar y expandir este script según tus necesidades específicas, como agregar más opciones de búsqueda, procesar resultados de búsqueda de diferentes maneras, o manejar errores y excepciones.
REM Sobrescribir el archivo hosts con el archivo temporal
move/y%tempfile%%hostsfile%>nul
echo Archivo hosts modificado correctamente.
En este script, se utiliza la variable dominio para especificar el nombre de dominio que deseas modificar, y la variable nueva_ip para especificar la nueva dirección IP que deseas asignarle. El script busca la línea que contiene el nombre de dominio en el archivo hosts, y si lo encuentra, lo reemplaza con la nueva dirección IP en un archivo temporal. Luego, sobrescribe el archivo hosts original con el archivo temporal, logrando así la modificación de la entrada.
Ten en cuenta que, al igual que en los ejemplos anteriores, necesitas tener privilegios de administrador en el sistema para ejecutar este script BATCH en DOS, y debes tener precaución al modificar el archivo hosts, siguiendo las políticas de seguridad y las leyes aplicables. Además, asegúrate de hacer copias de seguridad del archivo hosts antes de modificarlo, por si necesitas restaurarlo en caso de errores o problemas.
echo El archivo de nuevaslíneas no se encontró:%archivo_nuevas_lineas%
echo No se agregaron nuevaslíneas al archivo hosts.
)
REM Sobrescribir el archivo hosts con el archivo temporal
move/y%tempfile%%hostsfile%>nul
echo Archivo hosts modificado correctamente.
En este otro ejemplo, se utiliza la variable archivo_nuevas_lineas para especificar el nombre del archivo que contiene las nuevas líneas que se desean agregar. El script verifica si el archivo existe y, si es así, lee las líneas del archivo y las agrega al archivo temporal. Si el archivo no existe, muestra un mensaje de error indicando que no se encontró el archivo de nuevas líneas.
Si es un lector habitual de este blog y le gusta su contenido quizá quiera contribuir a su mantenimiento. Cualquier cantidad por pequeña que sea será bien recibida.