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 exitosaorden && orden
- Por lo contrario
||
(or) ejecuta la segunda orden solo si la primera a falladoorden || 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