1 2 3 4 5 6 7 |
#!/bin/bash cont=5 until [ $cont -lt 1 ]; do echo Vuelta numero : $cont let cont=cont-1 done |
1 2 3 4 5 6 7 |
#!/bin/bash cont=5 until [ $cont -lt 1 ]; do echo Vuelta numero : $cont let cont=cont-1 done |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#!/bin/bash var1=30 echo "Introduzca un numero, a ver si aciertas:" while true; do read var2 if [ $var1 = $var2 ]; then echo "Numero Correcto" break else echo "Numero incorrecto, vuelve a intentarlo :" fi done |
Evitar problemas de concurrencia
Si dos copias del script son iniciadas al mismo tiempo, es posible (aunque difícil, estas operaciones duran pocos milisegundos) que las dos copias lleguen al mismo tiempo al código que comprueba que el archivo $LOCK_FILE exista. Si esto sucede, ambas copias del script pueden determinar que el archivo no existe, y continuar su ejecución.
Esta clase de problemas en donde dos programas compiten por un recurso, sin que podamos determinar cuál de ellos lo obtiene, se conocen como race conditions («condiciones de carrera»). En muchos casos, cuando es posible, los evitamos usando operaciones atómicas [3].
Para este problema en particular, veremos dos variantes.
1.mkdir
Con mkdir tenemos una solución al problema, siempre que estemos dispuestos a usar un directorio y no un archivo como $LOCK_FILE. La orden
1 |
mkdir $LOCK_DIR |
tiene dos resultados posibles: si el directorio no existe, será creado, y mkdir saldrá con un código de éxito. Si el directorio existe, mkdir fallará y no habrá cambios en el sistema.
2.noclobber
BASH tiene una opción llamada noclobber, que hace que si intentamos redirigir salida (vía >) a un archivo que ya existe, la redirección falle. Basta entonces con escribir algo como:
1 2 3 4 5 |
set -o noclobber # se puede abreviar como set -C : > $LOCK_FILE if [[ $? != 0 ]]; # la redirección falló, el archivo existía previamente fi |
Para desactivar noclobber (como hacemos con las opciones de bash que modifican su comportamiento y usamos para una parte específica de nuestro script), debemos añadir una línea conteniendo set +C. Otra opción es utilizar una subshell, de tal manera que la shell que corre nuestro script no se vea afectada por el cambio, y por tanto no sea necesario desactivar nada:
1 2 3 4 |
(set -C; : > $LOCK_FILE) 2> /dev/null if [[ $? != 0 ]]; then # la redirección falló, el archivo existía fi |
Con estas mejoras, así es como nuestro script se ve ahora:
1 2 3 4 5 6 7 8 9 10 |
#!/bin/bash LOCK_FILE=/tmp/script.fulanito.lock trap 'rm $LOCK_FILE; exit $?' EXIT ( set -C; : > $LOCK_FILE ) 2>/dev/null if [[ $? == 0 ]]; then touch $LOCK_FILE #contenido del script else echo "Una copia anterior de este script sigue corriendo" fi |
Con este SCRIPT monitoreo en linea un archivo LOG, en el cual se controlan los tiempos de ejecución de las distintas fases, contranstandolas contra los tiempos estimados de ejecución de cada una de la fases. Si alguna es excedida en el tiempo de ejecución, el SCRIPT procede a emitir una alerta, la cual puede consistir en enviar un MAIL o grabar la información en un archivo de registro.- Probado en servidor AIX.
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 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
#!/bin/bash pvector=/usr01/home/monitor/shells/p$1vector.txt alerta=/usr01/home/monitor/shells/alerta.txt echo $logvector echo Fase Tiempo H.Inicio H.Fin Utilizado Excedido # leo en forma secuencial el archivo pvector el cual # tiene solo 2 campos : numero de fase y tiempo # de ejecucion while read fase ; do # leo los datso del archivo y se los asigno # a las variables fas=`echo $fase | cut -d " " -f 1` min=`echo $fase | cut -d " " -f 2` seg=`echo "scale=0; $min * 60" | bc` # Busco el patron indicado y capturo la linea # siguiente la cual contiene la fecha y hora # de comienzo de la Fase indicada # Si no enccuentra el PATRON se salta y lee # el siguiente registro del archivo if [ -f /APPADP01/home/vectprod/EXTERNOS_$3/bin/$2 ]; then logvector=/APPADP01/home/vectprod/EXTERNOS_$3/bin/$2 elif [ -f /APPADP01/home/vectprod/EXTERNOS_$3/bin/LOG/$2 ]; then logvector=/APPADP01/home/vectprod/EXTERNOS_$3/bin/LOG/$2 else echo "** ARCHIVO DE LOG *** NO EXISTE *****" read pausa break fi inicio=`cat $logvector | sed -n '/^Fase '$fas'/{n;p;}'` if [ "${inicio:-NULL}" = "NULL" ]; then continue fi hor1=`echo $inicio | cut -d " " -f 4` h11=`echo $hor1 | cut -d ":" -f 1` h12=`echo $hor1 | cut -d ":" -f 2` h13=`echo $hor1 | cut -d ":" -f 3` h14=`echo "$h13 + ($h12 * 60) + ($h11 * 3600)" | bc` h15=`echo "scale=0; $h14 / 60" | bc` bandera=no # Genero un ciclo infinito con el BUCLE FOR en donde # Comienzo a consultar si existe el patron de FIN # de la fase monitoreada - Si no encuentra el patron # Calcula la hora transcurrida y la verifica contra # el tiempo estimado de ejecucion # Si el tiempo es exedido procede a enviar un correo # para tomar las acciones que sean necesarias. for ((;;)); do if [ -f /APLI/home/prod/NOS_$3/bin/$2 ]; then logvector=/APLI/home/prod/NOS_$3/bin/$2 elif [ -f /APLI/home/prod/NOS_$3/bin/LOG/$2 ]; then logvector=/APLI/home/prod/NOS_$3/bin/LOG/$2 else echo "** ARCHIVO DE LOG *** NO EXISTE *****" read pausa break fi final=`cat $logvector | sed -n '/^Fin Fase '$fas'/{n;p;}'` if [ "${final:-NULL}" = "NULL" ]; then hact2=`echo $(date) | cut -d " " -f 4` hora1=`echo $hact2 | cut -d ":" -f 1` hora2=`echo $hact2 | cut -d ":" -f 2` hora3=`echo $hact2 | cut -d ":" -f 3` hora4=`echo "scale=0; $hora3 + ($hora2 * 60) + ($hora1 * 3600)" | bc` hora5=`echo "scale=0; $hora4 / 60" | bc` if [ $hora5 -gt $h15 ]; then tiempo=`echo "scale=0; $hora5 - $h15" | bc` fi if [ $h15 -gt $hora5 ]; then tiempo=`echo "scale=0; ( 1440 - $h15 ) + $hora5" | bc` fi if [ $tiempo -gt $min ]; then difer=`echo "$tiempo - $min" | bc` echo `date +%Y%m%d` `date +%H:%M:%S` $logvector FASE $fas $min $hor1 $tiempo $difer >> $alerta echo "$logvector FASE $fas $min $hor1 $tiempo $difer" | mail -s "ALERTA-VECTOR FASE $fas excedido en $difer MINUTOS" correo@tu.cl fi else bandera=si fi # Aqui consulta la variable "bandera" si su valor # es = a "si" procede a quebrar el bucle infinito # es decir finaliza la fase y debera seguir # con la siguiente if [ $bandera = si ]; then break fi sleep 900 done hor2=`echo $final | cut -d " " -f 4` h21=`echo $hor2 | cut -d ":" -f 1` h22=`echo $hor2 | cut -d ":" -f 2` h23=`echo $hor2 | cut -d ":" -f 3` # Trasnformo la hora a minutos h24=`echo "scale=0; $h23 + ($h22 * 60) + ($h21 * 3600)" | bc` if [ $h24 -gt $h14 ]; then difer=`echo "scale=0; $h24 - $h14" | bc` else difer=`echo "scale=0; (86400 - $h14) + $h24" | bc` fi if [ $h24 -eq $h14 ]; then difer=0 fi minutos=`echo "scale=0; $difer / 60" | bc` resto=`echo "scale=0; $minutos - $min" | bc` bien=1 if [ $resto -lt $bien ]; then resto=0 fi echo $fas $min $hor1 $hor2 $minutos $resto done <<< "`cat $pvector`" |
Substitución
Substituir «foo» por «bar» en todas las líneas
Sólo en la 1ra ocurrencia
sed ‘s/foo/bar/’
Sólo en la 3ra ocurrencia
sed ‘s/foo/bar/3’
En todas las ocurrencias
sed ‘s/foo/bar/g’
Sólo en la penúltima ocurrencia
sed ‘s/\(.*\)foo\(.*foo\)/\1bar\2/’
Sólo en la última ocurrencia
sed ‘s/\(.*\)foo/\1bar/’
Substituir «foo» por «bar» sólo en las líneas que contienen “plop”
sed ‘/plop/ s/foo/bar/g’
Substituir «foo» por «bar» menos en las líneas que contienen “plop”
sed ‘/plop/! s/foo/bar/g’
Substituir «Foo» o «foo» por “bar” en todas las líneas
sed ‘s/[Ff]oo/bar/g’
Substituir «azul», «blanco» o “rojo” por “verde”
sed ‘s/azul\|blanco\|rojo/verde/g’
Visualización
La 1ra línea (head -1)
sed q
Las 5 primeras líneas (head -5)
sed ‘5q’
sed ‘1,5!d’
La última línea (tail -1)
sed -n ‘$p’
sed ‘$!d»
Las 5 últimas líneas (tail -5)
sed -e :a -e ‘$q;N;6,$D;ba’
Las 2 últimas líneas (tail -2)
sed ‘$!N;$!D’
Sólo las líneas que coinciden con un patrón o expresión regular
sed -n ‘/patrón/p’
sed ‘/regexp/!d’
Sólo las líneas que no coinciden con un patrón o expresión regular
sed -n ‘/patrón/!p’
sed ‘/regexp/d’
La línea anterior a un patrón o expresión regular
sed -n ‘/patrón/{g;1!p;};h’
La línea que sigue a un patrón o expresión regular
sed -n ‘/regexp/{n;p;}’
Eliminación
Espacio y tabulación
Eliminar los espacios y las tabulaciones
Al inicio de línea
sed ‘s/^[ \t]*//
sed ‘s/^\s*//’ # Uso del parámetro «\s»
Al final de la línea
sed ‘s/[ \t]*$//’
Al inicio y al final de la línea
sed ‘s/^[ \t]*//;s/[ \t]*$//’
Línea vacía
Eliminar las líneas vacías
Todas las líneas vacías
sed ‘/^$/d’
sed ‘/./!d’
Sólo las del encabezado
sed ‘/./,$!d’
sed -nr ‘/./,$s/(.*)/\1/p’
Sólo las del final
sed -e :a -e ‘/^\n*$/ {$d;N;ba’ -e ‘}’
Intervalo regular
Eliminar una línea a intervalos regulares
Todas la líneas pares
sed ‘1~2d’
Todas la líneas impares
sed ‘2~2d’
Todas las n líneas a partir de la línea n
sed ‘3~2d’ # Todas les 2 líneas a partir de la línea 3
Diversos
Unir líneas
Unir líneas de 2 en 2
sed ‘$!N;s/\n//’
Unir líneas de 3 en 3
sed ‘$!N;s/\n//;$!N;s/\n//;’
Si una línea termina en un backslash (\), agregar la línea siguiente y reemplazar el final de línea (/n) por un espacio
sed -e :a -e ‘/\\$/N; s/\\\n/ /; ta’
Si un línea comienza con un signo igual (=), agregarla a la línea precedente y reemplazar el signo igual (=) por un espacio
sed -e :a -e ‘$!N;s/\n=/ /;ta’ -e ‘P;D’
Visualización sin tener cuenta de las mayúsculas y minúsculas
(Mostrar únicamente las líneas que coinciden con un patrón sin tener en cuenta las mayúsculas y minúsculas)
El comando sed posee un flag – ver [ Sed – Introducción a Sed – Parte 1]- que permite buscar un patrón sin tener en cuenta las mayúsculas y minúsculas, pero este flag se aplica únicamente al comando de substitución (comando s).
A continuaron veremos un truco que permite utilizar este flag para mostrar (o no mostrar) líneas que coinciden con un patrón dado sin tener en cuenta de las mayúsculas y minúsculas.
Para ello, tan solo hay que utilizar el comando de substitución “s” asociado al [ metacaracter «&»] y al flag “I”.
Ejemplo para mostrar únicamente las líneas que contienen el termino “patron” (o Patron, PATRON, pAtron, etc.)
sed -n ‘s/patron/&/Ip’ fichero
El siguinte ejemplo permite mostrar las lineas comprendidasen tre los patrones (al principio de linea) «Revisando puertos» y «Proceso ejecucion». Muestra solo ese fragmento del archivo :
cat $salida | sed -n ‘/^Revisando puertos/,/^Proceso en ejecucion/p’