Skip to content

105.2 Scripting

Scripting

Es un archivo de texto que contiene varios comandos para que el shell (interprete) los ejecute seguidos. su principal objetivo es automatizar tareas o conseguir objetivos que un solo comando no puede.

la primera linea siempre indica el interprete se denomina shebang en bash es #!/bin/bash

parametros

$0-9    # argumentos pasados a una finción $0 nombre del script 
${10}   # argumentos superiores o iguales a 10 se indican con {}
$#      # Se expande al número de argumentos pasados al comando
$*      # todos los parametros. se presentan en una sola cadena separado por espacios
$@      # todos los argumentos. en una lista
"$@"    # todos los argumentos. entre comillas

variables

Una variable puede ser alfanumérica pero nunca empezar por número, las mayúsculas y minúsculas se diferencian, no es lo mismo $VAR que $var.

variable="contenido"     # muy importante no dejar espacios
# ver variable
echo $variable
echo ${variable}

Predefinidas

$0  # nombre del script
$!  # PID del ultimo programa ejecuado
$$  # PID del proceso asignado al script
$?  # resultado devuelto por el ultimo proceso ejecutado

variables de entorno como por ejemplo $PATH , se pueden ver las disponibles con printenv

read arg1
read arg1 arg2
read -p "introduce tu nombre: " arg1

Aritmetic expansion

Cálculos matemáticos

echo $(( 2 * 4 ))
8
max=30
echo $(( 365 - $max )) 
335

#  operadores aritmeticos
+    suma
-     resta
\*   multiplicar
/     dividir  
%   modulo (resto )

Test

Test cheque tipo de archivos y compara valores.

todas sus opciones en man test

# algunas de sus opciones para ficheros
-L es link
-f fichers regulares
-d directorio
-e existe
-o dispositivo de bloques
-x archivo ejecutable
-w permisos de escritura
-r permisos de lectura
-n not null
-s su tamaño es mayor a 0 

# en cadenas
-n "algo"    cadena no vacia true
-z ""    cadena vacia true
=    iguales
!=    diferentes
=~    conpara con expresion regular

# comparadores numericos
-gt    >
-lt    <
-ge    >=
-le    <=
-eq    ==
-ne    !=
-a    and
-o    or
!     not

La condición realmente ejecuta un test, que devuelve true o false.

sintaxis:

test $n -lt 18
[ $n -lt 18 ]

test se a actualizado y trae algunas funcionalidades extra, como:

# si un archivo tiene espacios en su nombre
if [ -f "$file" ]
if [[ -f $file ]]
# aceptar expresiones regulares
if [ "$answer" = y -o "$answer" = yes ]
if [[ $answer =~ ^y(es)?$ ]]
# acepta parentesis y las expresiones && || !
[ 5 -lt 7 -a ! 5 -gt 7 ]
[[ 5 -lt 7 && !(5 -gt 7) ]] 
# permite comparar texto segun su numero asci
[[ "a" < "z" ]]

Array

${#variable}    # contar caracteres 

lista=(2 8 5 7 6)
echo ${lista[@]} 
2 8 5 7 6   # muestra lista completa

echo ${lista[2]}
5  # muestra el item de la posición 2

echo ${#lista[@]}  
5  # items dentro de la lista

echo ${!lista[@]}  
0 1 2 3 4  # posiciones de la lista ocupadas

Slicing

echo ${lista[@]:2}
5 7 6  # muestra de posición 2 hasta el final  

echo ${lista[@]:1:2}
8 5  # muestra desde la posición 1 dos números

Añadir y quitar items

# añadir item --------------
lista=(uno dos tres)
lista[3]=cuatro

echo ${lista[@]}  
uno dos tres cuatro

lista[${#lista[@]}]=”algo”       # añade al final de la lista
echo ${lista[@]}  
uno dos tres cuatro algo

# quitar item --------------
lista=(uno dos tres)
unset lista[2]

echo ${lista[@]}  
uno dos

Condicionales

Sentencia if

if [ $edad -ge 18 ]
then
    echo "Mayor de edad"
else
    echo "Menor de edad"
fi

Sentencia elif

if [ $edad -lt 18 ]
then
    echo "Menor edad"
elif [ $edad -lt 65 ]
then
    echo "Edad laboral"
else
    echo "jubilat"
fi

Prohibido repetir la misma instrucción dentro de if, elif, else, etc.. a no se que sea absolutamente necesario.

&& y ||

Estos condicionales se utilizan tanto en el shell como en scripting, es importante no confundirlos con los condicionales de -o y -a de test.

  • El condicional && (and) ejecuta la segunda orden solo si la primera a sido exitosa orden && orden
  • Por lo contrario || (or) ejecuta la segunda orden solo si la primera a fallado orden || orden
 ping -c1 google.es &> /dev/null && echo "Esta web existe"
Esta web existe

➜ ping -c1 desconocida.es &> /dev/null || echo "Esta web NO existe"
Esta web NO existe

Case

Case evalúa valores

lletra=$1
case $lletra in
   'a'|'e'|'i'|'o'|'u')
        echo "$lletra es una vocal"
        ;;
    *) 
        echo "$lletra es una constant"
        ;;
esac
exit 0
  • indicas los valores a evaluar y si no existe el * es el comodín, como si fuera un else.

shopt -s nocasematch antes de la construcción de case permitirá la coincidencia de patrones sin distinción entre mayúsculas y minúsculas. Las opciones modificadas deshopt solo son efectivas en la sesión actual, si se quiere desactivar la opción de nuevo shopt -u nocasematch lo desactivará.

Comand substitution

Ejecutar una orden para ser ejecutada por otra orden:

Ejemplo:

 file $(ls)
test.txt: ASCII text
script.sh: Bourne-Again shell script, ASCII text executable

➜ dpkg -S $(which ip)  
iproute2: /bin/ip

o encadenando

rpm -ql $(rpm -qf $( which ip ) )
  • Primero se ejecuta which
  • Tercero rpm queri file con todo el resultado
  • cuarto rpm queri list

Depurar

Bash tiene argumentos de depuración que indica que esta haciendo el script, mostrando cada linea del código o asignaciones de variables etc....

bash -v script.sh   # muestra cada línea del codigo mientras se ejecuta
bash -x script.sh   # muestra como se van asignando variables, etc..
#!/bin/bash -xv     # se puede indicar directamente desde el shebang

Ejemplo:

 cat script.sh 
#!/bin/bash
nombre=$1
echo "La variable asignada es $nombre" bash -x script.sh paco 
+ nombre=paco
+ echo 'La variable asignada es paco'
La variable asignada es paco

Bucles

for

Itera per a cada element d'una llista finita

llista="per pau edu anna"
for nom in "$llista"
do
    echo $nom
done

for i in $(seq 1 1 5); # ( inicio incremento final ) 
do
    echo $i
done

for ((  i = 0 ;  i <= 5;  i++  ))  # ( inicio ; final ; incremento ) 
do
  echo " $i "
done

for i in $(ls *.txt); # con coman substitution se puede pasar cualquier lista
do
    echo $i
done

While

con while hay que tener en cuenta la condición para no crear un bucle infinito

CONTADOR=0
while [  $CONTADOR -lt 5 ]; do
       echo El contador es $CONTADOR
       let CONTADOR++
done    

# ller lineas por entrada estandar y numerarlas
cont=1
while read -r line
do
    echo "$cont: $line"
    cont=$((cont+1))
done

continue, break

continue corta la iteración de esa vuelta del bucle y vuelve a la condición para evaluar la siguiente vuelta si la hay.

break corta el bucle y sale .

# ejemplo continue --------------- cat continue.sh 
#!/bin/bash
for i in $(seq 5 8 ); do
    if [ $i -eq 7 ]; then
        continue
    fi
    echo "variable i = $i"
done bash continue.sh
variable i = 5
variable i = 6
variable i = 8

# ejemplo break ------------ cat break.sh 
#!/bin/bash
for i in $(seq 5 8 ); do
    if [ $i -eq 7 ]; then
        break
    fi
    echo "variable i = $i"
done bash break.sh
variable i = 5
variable i = 6

Funciones

Sintaxis

function nombreFuncion {
    # comandos o instrucciones
}

# también hacepta
nombreFuncion() {
    # comandos o instrucciones
}

Ejemplo

tabla(){
    for variable in {0..10}
    do
        echo "$variable * $1 = $(($variable*$1))"
    done
}

case $1 in
    1) tabla 5;;
    2) tabla 6;;
esac

# output ----------------  bash func.sh 2
0 * 6 = 0
1 * 6 = 6
2 * 6 = 12
...
  • si dentro de la función asignamos una variable con local num=2 no lo guarda al salir de la función.
suma(){
    result=$(($1 + $2))
    return $result
}
suma 10 20
echo $result
-------
30
  • para devolver un valor tenemos que utilizar return

Modulo de funciones

Para usar un modulo personalizado creamos un archivo con todas las funciones y lo exportamos al shell actual.

funciones.sh

#!/bin/bash
# modulo funcions
# ----------------------------

function hola(){
    echo "hola, bon dia"
    return 0
}

function suma(){
    echo $(($1 + $2))
    return 0
}

Exporto el archivo funciones con ". ", una vez exportado puedo utilizar sus funciones en el shell.

 . ./funciones.sh
➜ hola
hola, bon dia
➜ suma 5 5
10

Printf

printf se usa para mostrar output, tiene algunas mejoras respecto al comando echo

echo -e "Usuario:\t$USER\nShell:\t$SHELL"
printf "Usuario:\t%s\nShell:\t%s\n" $USER $SHELL
Usuario:    debian
Shell:  /usr/bin/zsh


MSG='Usuario:\t%s\nShell:\t%s\n'
printf "$MSG" $USER $SHELL

man 3 printf