BASH CookBook

La idea de esta sección es la de almacenar algunas ideas de cómo hacer cosas en BASH

Una fuente inagotable de comandos y recetas BASH es:

Cómo asignar valores a variables con read

Es habitual correr comandos que dan 2 o más resultados y queremos asignar estos valores a dos o más variables. Podemos usar el manco read del bash, pero… read pretende leer lineas de texto de un archivo.

Si lo que queremos es que lea valores para dos o más variables que provienen de stdout de otros comandos o de un pipe, podemos hacerlo con here files:

read a b <<< $(echo 1 2); echo $a $b

Con el uso de «< podemos forzar que read lea de stdout y que asigne datos a las variables a y b en función de lo que devuelva por stdout lo que se ejecuta dentro del subshell $(…)

Por ahora es la única manera que encontré de asignar valores obtenidos como resultado de un comando a más de una variable del bash.

Porque lo habitual es

a=$(echo 1 2)

con lo cual la variable $a toma el valor “1 2”, pero la idea es que “1” vaya a una variable y “2” vaya a otra variable.

Generación de números aleatorios

  • La forma más sencilla es usar la variable $RANDOM, que devuelve números entre 0 y 32767

para más control, si queremos rangos menores, podemos usar la operación módulo, por ej. para un número entre 0 y 99:

 let R=$RANDOM%100
 echo $R

para un número entre 1 y 100:

 let R=$RANDOM%100+1
  • Otra forma de generar un número aleatorio entre 1 y 100 consiste en usar la siguiente receta:
seq 1 100|shuf|head -1

explicación: seq genera la secuencia, shuf genera una permutación aleatorio y head devuelve el primer número de la lista

  • Otra receta, usando octal dump:
od -vAn -N2 -i < /dev/urandom

explicación: con esa sentencia se generan números entre 0 y 65535

  • -v: output duplicates
  • -An: no offset printed (no imprime la posición de los bytes en la salida)
  • -N2: número de bytes tomados del archivo (en este caso 2, si uso 1 entonces los números son entre 0 y 255)
  • -i: formato del número: entero sin signo (ver otras opciones en man od)

Números Aleatorios en otras Bases (Hexadecimal, binario, octal, etc.)

HEXADECIMAL

$(dd if=/dev/random bs=1 count=1 2>/dev/null | od -An -tx1 | tr -d ' \t\n')
od -N32 -x < /dev/urandom | head -n1 |  cut -b9- | sed 's/ //gi'
openssl rand -hex 16
head -c 6 /dev/urandom | od -x | head -n 1 | sed -e 's/^0* //' -e 's/ //g'
cat /dev/urandom | tr -cd 'a-f0-9' | head -c 2
hexdump -n 16 -v -e '/1 "%02X"' /dev/urandom

Dígitos hexadecimales:

printf "%x" $(($RANDOM%16))

Cómo generar una MAC aleatoria

Por ejemplo, queremos generar una MAC aleatoria, dada una ID de fabricante determinada: 00-60-2F-xx-xx-xx

echo -n 00-60-2F; dd bs=1 count=3 if=/dev/random 2>/dev/null |hexdump -v -e '/1 "-%02X"'

o, una manera alternativa de generar ternas de HEX:

printf "%02x-%02x-%02x" $(($RANDOM%256)) $(($RANDOM%256)) $(($RANDOM%256))

Cómo chequear en bash una MAC

[[ $MAC =~ ([a-zA-Z0-9]{1,2}:){5}[a-zA-Z0-9]{2} ]]

Esto devuelve 0 si $MAC corresponde a una MAC address y 1 en caso contrario

Cómo extraer números IPs de un archivo de texto

Se puede usar el comando grep que extrae un listado de números IPs:

grep -E -o '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)' archivo.log

Strings y substrings

Sea var=9357. Para saber el largo de un string en bash, se puede usar el #:

echo ${#var}
4

Si quiero extrar un substring, puedo usar : para especificar la posición de arranque del substring que me interese y luego el largo del substring. ejemplo:

echo ${var:2:2}
57
echo ${var:0:1}
9

Recordar que el primer índice es 0 (cero)!!!

Remover caracteres no numéricos de un string

Desde el propio bash:

VAR="Berp.,-1234grok73"

Pattern substitution: con /, en el siguiente ejemplo se sustituyen dígitos por nada, es decir que se eliminan los dígitos

echo ${VAR//[[:digit:]]/}
Berp,.-grok

Lo mismo, pero ahora con caracteres alfabéticos

echo ${VAR//[[:alpha:]]/}
.,-123473

Si queremos eliminar todos los caracteres alfanuméricos:

echo ${VAR//[[:alpha:][:digit:]]/}
.,-

Ejemplo con tr:

tr -dc '0-9' <<< "a12.345-&3q4"
1234534

Ejemplo con sed:

sed 's/[^0-9]*//g' <<< "a12.345-&3q4"
1234534

Descomponer un string en sus caracteres (o un número en sus dígitos)

Sabiendo el largo del string, puedo usar un for loop para descomponerlo

var=9357
for (( i=0; i < ${#var}; i++ )); do echo ${var:$i:1}; done

9
3
5
7

Para almacenarlos en un array

var=9357
for (( i=0; i < ${#var}; i++ )); do digits[$i]=${var:$i:1}; done
echo ${digits[0]}
9

Ojo: no dejar espacio entre la variable y el signo de igual para que funcione la asignación en bash.

Descomponer un string usando un separador

Sea por ejemplo:

var="uno:dos:tres:cuatro"

Podemos descomponer ese string, usando : como separador, usando el comando read

IFS=':' read -ra array <<< "$var"
for i in "${array[@]}"; do  echo $i; done

uno
dos
tres
cuatro

Hacer producto escalar de vectores enteros

vec1=(1 2 3 4)
vec2=(5 6 7 8)
let e=0
for (( i=0; i < ${#vec1[@]}; i++ )); do let e=$e+${vec1[$i]}*${vec2[$i]}; done
echo $e
70

Ojo: en el for loop hay que usar ${#vec1[@]} para saber el largo del array vec1.