Shell Scripting#
Dar permisos de ejecución a un script:
$ cat script.sh
#!/bin/bash
nombre=$(whoami)
echo hola ${nombre}
$ chmod +x script.sh
$ ./script.sh
hola dani
Entrada de datos#
Argumentos de entrada
$ cat args.sh #!/bin/bash X=$1 Y=$2 Z=$3 echo X=$X Y=$Y Z=$Z echo "En total hay $# argumentos : $@" $ ./args.sh uno dos tres X=uno Y=dos Z=tres En total hay 3 argumentos : uno dos tres
shift desplaza los argumentos el número de veces que aparezca
$ cat args.sh #!/bin/bash shift X=$1 Y=$2 Z=$3 echo X=$X Y=$Y Z=$Z echo "En total hay $# argumentos : $@" $ ./args.sh uno dos tres X=dos Y=tres Z= En total hay 2 argumentos : dos tres $ cat args.sh #!/bin/bash shift shift X=$1 Y=$2 Z=$3 echo X=$X Y=$Y Z=$Z echo "En total hay $# argumentos : $@" $ ./args.sh uno dos tres X=tres Y= Z= En total hay 1 argumentos : tres
En el caso de que queramos que se tome un argumento por defecto:
$ cat args.sh #!/bin/bash X=${1:-hola} Y=${2:-33} Z=${3:-$(whoami)} echo X=$X Y=$Y Z=$Z echo "En total hay $# argumentos : $@" $ ./args.sh uno dos tres X=uno Y=dos Z=tres En total hay 3 argumentos : uno dos tres $ ./args.sh X=hola Y=33 Z=dani En total hay 0 argumentos :
En el caso de que queramos que el programa se pare a preguntar por el valor de una variable utilizaremos read
$ cat args.sh #!/bin/bash echo "Hola, ¿Cómo te llamas?" read X echo Hola $X $ ./args.sh Hola, ¿Cómo te llamas? dani Hola dani
Bucles y condicionales#
Bucles
$ cat for.sh #!/bin/bash for ((i=0;i<6;i++)) do echo $i done $ ./for.sh 0 1 2 3 4 5
Bucles y condicionales
$ cat for.sh #!/bin/bash for ((i=1;i<6;i++)) do X=3 if [ $i -gt $X ] then echo $i es mayor que $X else echo $i es menor o igual que $X fi done $ ./for.sh 1 es menor o igual que 3 2 es menor o igual que 3 3 es menor o igual que 3 4 es mayor que 3 5 es mayor que 3
Podríamos sustituir la linea if [ $i -gt $X ] por :
if [[ $i -gt $X ]] if test $i -gt $X
Evaluación de condiciones numéricas
if test $i -gt $X # -gt grater than if test $i -ge $X # -gt grater or equal than if test $i -lt $X # -lt less than if test $i -eq $X # -eq equal than if test $i -ne $X # -ne not equal than
Comparación de cadenas
$ grep '/bin/bash' file.dat | grep -v root dani:x:1001:1000:dani,,,:/home/dani:/bin/bash ramon:x:1002:1000:ramon,,,:/home/ramon:/bin/bash pablo:x:1003:1000:pablo,,,:/home/pablo:/bin/bash alvaro:x:1004:1000:alvaro,,,:/home/alvaro:/bin/bash cris:x:1005:1000:cris,,,:/home/cris:/bin/bash ana:x:1006:1000:ana,,,:/home/ana:/bin/bash elvira:x:1007:1000:elvira,,,:/home/elvira:/bin/bash $ cat for2.sh #!/bin/bash for i in $(grep '/bin/bash' file.dat | grep -v root|cut -d':' -f1) do echo $i done $ ./for2.sh dani ramon pablo alvaro cris ana elvira $ cat for2.sh #!/bin/bash for i in $(grep '/bin/bash' file.dat | grep -v root|cut -d':' -f1) do if test $i == "dani" then echo $i encontrado fi done $ ./for2.sh dani encontrado
Podríamos sustituir la linea if test $i == «dani» por:
if [ $i == "dani" ] if [[ $i == "dani" ]]
Evaluación de condiciones con cadenas de caracteres:
Str1 == Str2 # Returns true if the strings are equal Str1 != Str2 # Returns true if the strings are not equal -n Str1 # Returns true if the string is not null -z Str1 # Returns true if the string is null #Ejemplo: cadena="Hola" if [ -n "$cadena" ] #no olvidar "" then echo "La cadena no está vacía" else echo "La cadena está vacía" fi La cadena no está vacía
Otras forma de hacer bucles
for i in a b c do echo $i done a b c i=0 while [ $i -lt 4 ] do i=$(($i+1)) echo $i done 1 2 3 4 #seguirá hasta que el archivo file.dat sea creado while ! test -e file.dat do sleep 1s date done
Juntar expresiones and y or
for i in a b c do for j in a b c do if [ $i == $j ] && [ $j == "a" ] then echo $i $j ',i j son iguales y j = a' fi if [ $i == $j ] || [ $j == "a" ] then echo $i $j ',i j son iguales o j = a' fi done done a a ,i j son iguales y j = a a a ,i j son iguales o j = a b a ,i j son iguales o j = a b b ,i j son iguales o j = a c a ,i j son iguales o j = a c c ,i j son iguales o j = a
Estructura básica de if, elif, else
if [ condición1 ]; then # Código a ejecutar si condición1 es verdadera elif [ condición2 ]; then # Código a ejecutar si condición2 es verdadera y condición1 es falsa else # Código a ejecutar si ninguna de las condiciones anteriores es verdadera fi
Sintaxis básica de case
case $variable in patrón1) # Código a ejecutar si $variable coincide con patrón1 ;; patrón2) # Código a ejecutar si $variable coincide con patrón2 ;; *) # Código a ejecutar si no coincide con ninguno de los patrones anteriores ;; esac
Propiedades de archivos y carpetas#
$ cat file.sh
#!/bin/bash
archivo=$1
if test -e $archivo #True si existe
then
if test -d $archivo
then
echo "La carpeta $archivo existe"
fi
if test -f $archivo
then
echo "El archivo $archivo existe"
fi
if test -r $archivo
then
echo "tiene permisos de lectura"
fi
if test -w $archivo
then
echo "tiene permisos de escritura"
fi
if test -x $archivo
then
echo "tiene permisos de ejecución"
fi
else
echo $archivo" no existe "
fi
$ echo hola > hola.dat
$ chmod +rwx hola.dat
$ ./file.sh hola.dat
El archivo hola.dat existe
tiene permisos de lectura
tiene permisos de escritura
tiene permisos de ejecución
$ mkdir dir
$ chmod +rw dir
$ chmod -x dir
$ ./file.sh dir
La carpeta dir/ existe
tiene permisos de lectura
tiene permisos de escritura
Funciones#
function Suma(){
a=$1
b=$2
c=$((a+b))
echo $c
}
$ Suma 1 2
3
Arrays#
$ palabra=("PYTHON" "LINUX" "BASH" "GITHUB" "DOCKER")
$ echo ${palabra[0]}
PYTHON
$ echo ${palabra[1]}
LINUX
$ longitud=${#palabra[@]}
$ echo $longitud
5
$ for((i=0;i<$longitud;i++))
> do
> echo palabra[$i]=${palabra[$i]}
> done
palabra[0]=PYTHON
palabra[1]=LINUX
palabra[2]=BASH
palabra[3]=GITHUB
palabra[4]=DOCKER
$ for i in ${palabra[@]}
> do
> echo $i
> done
PYTHON
LINUX
BASH
GITHUB
DOCKER
$ A[0]=1
$ echo ${A[0]}
1
$ echo ${A[1]}
$ for i in 1 2 3 4
> do
> A[$i]=$i
> done
$ for i in 1 2 3 4
> do
> echo ${A[$i]}
> done
1
2
3
4
$ echo $((${A[1]}+${A[2]}))
3
Escritura de archivos#
$ tunombre=dani
$ cat << EOF > new_file.dat
Mi nombre es $tunombre
hoy es $(date)
EOF
$ cat new_file.dat
Mi nombre es dani
hoy es mié 12 oct 2022 16:37:57 CEST
Podemos hacer lo mismo:
$ echo "Mi nombre es $tunombre
hoy es $(date)" >> new_file.dat
AWK#
awk es una herramienta de procesamiento de texto y manipulación de datos, la estructura básica es awk 'patrón { acción }' archivo
.
Variables especiales de awk:
$0: Toda la línea actual.
$1, $2, …, $n: Campos (columnas) de la línea.
NR: Número de línea actual.
NF: Número de campos en la línea actual.
FS: Delimitador de campos (por defecto es espacio).
OFS: Delimitador de salida (por defecto es espacio).
Vemos a continuación ejemplos
$ cat datos.dat
maria 8.9 54.2
pedro 15.2 20.2
ana 7.6 5.6
carlos 20.3 8.9
elena 10.8 43.2
sergio 3.4 4.4
laura 6.7 5.5
david 9.2 6.6
$ awk '{ print $1 }' datos.dat
maria
pedro
ana
carlos
elena
sergio
laura
david
$ awk '{ print $1,$3 }' datos.dat
maria 54.2
pedro 20.2
ana 5.6
carlos 8.9
elena 43.2
sergio 4.4
laura 5.5
david 6.6
#sumar los valores de la columna 3
$ awk '{ suma += $3 } END { print suma }' datos.dat
148.6
#Calcular promedio
$ awk '{ suma += $3 } END { print suma/NR }' datos.dat
18.575
#contar el número de líneas
$ awk 'END { print NR }' datos.dat
8
#imprimir lineas con un número específico de campos
$ awk 'NF == 3 { print }' datos.dat
maria 8.9 54.2
pedro 15.2 20.2
ana 7.6 5.6
carlos 20.3 8.9
elena 10.8 43.2
sergio 3.4 4.4
laura 6.7 5.5
david 9.2 6.6
$ awk 'NF == 2 { print }' datos.dat
#agregar texto adicional a la salida
$ awk '{print "Linea:", $0 }' datos.dat
Linea: maria 8.9 54.2
Linea: pedro 15.2 20.2
Linea: ana 7.6 5.6
Linea: carlos 20.3 8.9
Linea: elena 10.8 43.2
Linea: sergio 3.4 4.4
Linea: laura 6.7 5.5
Linea: david 9.2 6.6
#usar condiciones
$ awk '$2 > 10 { print }' datos.dat
pedro 15.2 20.2
carlos 20.3 8.9
elena 10.8 43.2
$ awk '$2 > 10 && $3 > 10 { print }' datos.dat
pedro 15.2 20.2
elena 10.8 43.2
$ awk '$2 > 10 || $3 > 10 { print }' datos.dat
maria 8.9 54.2
pedro 15.2 20.2
carlos 20.3 8.9
elena 10.8 43.2
#sumar columnas
$ awk '{ print $2 + $3 }' datos.dat
63.1
35.4
13.2
29.2
54
7.8
12.2
15.8
$ awk '{suma=$2+$3 ; print $1, $2, $3, suma }' datos.dat
maria 8.9 54.2 63.1
pedro 15.2 20.2 35.4
ana 7.6 5.6 13.2
carlos 20.3 8.9 29.2
elena 10.8 43.2 54
sergio 3.4 4.4 7.8
laura 6.7 5.5 12.2
david 9.2 6.6 15.8
#sumar la filas y mostrar solo al final el total
$ awk '{suma +=$2+$3} END {print "Total:",suma }' datos.dat
Total: 230.7
#mostrar las columnas 1, 3 y 4 de /etc/passwd separadas por -
$ cat /etc/passwd | awk 'BEGIN{FS=":";OFS=" - "} {print $1,$3,$4}'