Ejercicios de shell scripting#
disk.sh#
Crea un script llamado disk.sh que imprima por pantalla el porcentaje que esta ocupada la partición /home. Tiene que quedar:
75% /home
#!/bin/bash
df -h | grep home | tr -s ' '| cut -d' ' -f5-
mem.sh#
Crea un script llamado mem.sh, obtiene solamente la memoria en MB ocupada y haz que se escriban en un archivo llamado free.log cada vez que se ejecute, sin borrar el anterior registro.
#!/bin/bash
free -h | grep Mem | tr -s ' ' | cut -d' ' -f4 >> free.log
mac.sh#
Crea un script llamado mac.sh que obtiene la MAC de tu tarjeta de red
#!/bin/bash
ip link show enp2s0 | grep link | tr -s ' ' | cut -d' ' -f3
listar_usuario_grupo.sh#
Crea un script llamado listar_usuario_grupo.sh que saque por pantalla el nombre de los usuarios que hay creados en el sistema y al grupo que pertenecen, por ejemplo
alumno1 : smr1
alumno2 : smr1
alumno3 : asir1
alumno4 : asir2
#!/bin/bash
for i in $(cat /etc/passwd | grep bash | grep -v root | cut -d':' -f1)
do
groups $i
done
lastlog_ip.sh#
Crea un script llamado lastlog_ip.sh que muestre un listado ordenado con el nº de veces que se ha logueado cada ip, por ejemplo
16 10.2.104.100
11 10.2.3.100
10 139.47.103.76
9 10.2.105.100
8 2.153.195.106
8 10.2.4.100
8 10.2.105.106
#!/bin/bash
for i in $(last -w | tr -s ' ' | cut -d' ' -f3 | sort | grep '\.' | uniq);
do
echo $(last -w| grep -c $i) $i
done | sort -rn
#last -w | tr -s ' ' | cut -d' ' -f3 | grep '\.' | sort | uniq -c | sort -r
lastlog.sh#
Crea un script llamado lastlog.sh que muestre un listado ordenado con el nº de veces que se ha logueado cada usuario y el grupo al que pertenecen, por ejemplo
44 alumno1 smr1
32 alumno2 smr1
14 alumno3 asir1
4 alumno4 asir2
#!/bin/bash
for i in $(last -w | sort | cut -d' ' -f1 | uniq | egrep -v reboot | egrep -v wtmp)
do
echo $(last -w| grep -c $i) $i $(groups $i | cut -d':' -f2)
done | sort -rn
#last -w | tr -s ' ' | cut -d' ' -f1 | sort | uniq -c | sort -r
tabla_multiplicar_read.sh#
Crea un script llamado tabla_multiplicar_read.sh que pide un número al usuario y muestre su tabla de multiplicar
#!/bin/bash
echo "Introduce un número para mostrar su tabla de multiplicar: "
read numero
for ((i=1;i<11;i++))
do
resultado=$((numero * i))
echo "$numero x $i = $resultado"
done
tabla_multiplicar_read.sh#
Crea un script llamado tabla_multiplicar.sh, ahora no preguntará por el número al usuario y haz muestre su tabla de multiplicar cuando se ejecute por ejemplo ./tabla_multiplicat.sh <N> siendo <N> un numero del 1 al 10.
En el caso de ejecutar
./tabla_multiplicat.sh --helpmostrara un mensaje de ayuda (consejo utiliza una función)En el caso de ejecutar
./tabla_multiplicar.sh X Y Z ..., es decir con más de un argumento saldrá un mensajeNo se puede dar más de un argumentoEn el caso de ejecutar
./tabla_multiplicar.shsin argumentos se ejecutara la opción de --help
#!/bin/bash
mostrar_ayuda() {
echo "Uso: ./tabla_multiplicar.sh [número]
Este script muestra la tabla de multiplicar del número que se le pase como argumento.
Opciones:
--help Muestra este mensaje de ayuda.
Ejemplos:
./tabla_multiplicar.sh 4 Muestra la tabla de multiplicar del 4."
}
if [[ $# -eq 0 ]]
then
# Sin argumentos: mostrar ayuda
mostrar_ayuda
elif [[ $1 == "--help" ]]
then
mostrar_ayuda
else
numero=$1
for ((i=1;i<11;i++))
do
resultado=$((numero * i))
echo "$numero x $i = $resultado"
done
fi
#!/bin/bash
mostrar_ayuda() {
echo "Uso: ./tabla_multiplicar_array.sh [número]
Este script muestra la tabla de multiplicar del número que se le pase como argumento.
Opciones:
--help Muestra este mensaje de ayuda.
Ejemplos:
./tabla_multiplicar.sh 4 Muestra la tabla de multiplicar del 4."
}
if [[ $# -eq 0 ]]
then
# Sin argumentos: mostrar ayuda
mostrar_ayuda
elif [[ $1 == "--help" ]]
then
mostrar_ayuda
else
numero=$1
for ((i=1;i<11;i++))
do
A[$i]=$i
done
longitud=${#A[@]}
for((i=1;i<$longitud;i++))
do
echo "$numero x ${A[$i]} = $(($numero * ${A[$i]}))"
done
fi
imag.sh#
Crea una carpeta llamada imagenes, entra dentro y ejecuta los siguiente comandos:
for i in jpeg jpg png gif tiff bmp svg
do
for((j=0;j<10;j++))
do
echo imag_${RANDOM}.$i > imag_${RANDOM}.$i
done
done
Crea un script llamado imag.sh que cambie todas extensiones de todos los archivos a png conservando el nombre
#!/bin/bash
for i in imag_*
do
mv $i $(echo $i | cut -d'.' -f1).png
done
temperatura.sh#
Crea un script llamado temperatura.sh, que lea las temperatura del archivo temperatura.dat y saque por pantalla la temperatura media
#!/bin/bash
nlineas=$(wc -l temperatura.dat | cut -d' ' -f1)
T=0.00
for((i=1;i<=$nlineas;i++))
do
T=$(echo "scale=2; $T+$(head -$i temperatura.dat | tail -1)" | bc -l)
done
T_media=$(echo "scale=2; $T/$nlineas" | bc -l)
echo "Tenemos $nlineas temperaturas, de media T = $T_media"
#!/bin/bash
media=$(awk '{ suma += $1 } END { print suma/NR }' temperatura.dat )
ntemperaturas=$(awk 'END { print NR }' temperatura.dat)
echo "Tenemos $ntemperaturas temperaturas, de media T = $media"
#!/bin/bash
nlineas=$(wc -l temperatura.dat | cut -d' ' -f1)
for((i=1;i<=$nlineas;i++))
do
T[$i]=$(head -$i temperatura.dat | tail -1)
done
suma=0.00
for((i=1;i<=$nlineas;i++))
do
suma=$(echo $suma+${T[$i]} | bc -l)
done
echo $suma
T_media=$(echo "scale=2; $suma/$nlineas" | bc -l)
echo "Tenemos $nlineas temperaturas, de media T = $T_media"
meteo.sh#
Crea un script llamado meteo.sh que lea los datos de una estación meteorológica del archivo meteo.dat, cada línea es un día con cuatro columnas: día, temperatura mínima, temperatura máxima y humedad
01/06 12.5 22.1 65
02/06 10.2 24.0 58
03/06 14.0 26.5 60
Se pide:
La temperatura mínima media, la máxima media y la humedad media, con un decimal.
El día más caluroso y el día más frío.
El día con mayor amplitud térmica (temperatura máxima - mínima).
La salida tiene que quedar:
./meteo.sh
Temperatura mínima media : 12.3 ºC
Temperatura máxima media : 24.1 ºC
Humedad media : 61.5 %
Día más caluroso : 06/06 (29.6 ºC)
Día más frío : 08/06 (8.7 ºC)
Día con mayor amplitud : 09/06 (16.5 ºC)
Consejos:
readpuede leer varias variables a la vez:while read dia tmin tmax hum, cada columna llega a una variable sin necesidad decut.Con decimales no se puede comparar con
-gto-lt, compara con bc:$(echo "$tmax > $t_caluroso" | bc -l)devuelve 1 si es cierto.
#!/bin/bash
archivo="meteo.dat"
n=0
sum_min=0
sum_max=0
sum_hum=0
dia_caluroso=""
t_caluroso=-100
dia_frio=""
t_frio=100
dia_amplitud=""
amplitud_max=0
while read dia tmin tmax hum
do
n=$((n+1))
sum_min=$(echo "$sum_min + $tmin" | bc -l)
sum_max=$(echo "$sum_max + $tmax" | bc -l)
sum_hum=$(echo "$sum_hum + $hum" | bc -l)
# con decimales no podemos usar -gt o -lt, comparamos con bc
if [ $(echo "$tmax > $t_caluroso" | bc -l) -eq 1 ]
then
t_caluroso=$tmax
dia_caluroso=$dia
fi
if [ $(echo "$tmin < $t_frio" | bc -l) -eq 1 ]
then
t_frio=$tmin
dia_frio=$dia
fi
amplitud=$(echo "$tmax - $tmin" | bc -l)
if [ $(echo "$amplitud > $amplitud_max" | bc -l) -eq 1 ]
then
amplitud_max=$amplitud
dia_amplitud=$dia
fi
done < $archivo
echo "Temperatura mínima media : $(echo "scale=1; $sum_min / $n" | bc) ºC"
echo "Temperatura máxima media : $(echo "scale=1; $sum_max / $n" | bc) ºC"
echo "Humedad media : $(echo "scale=1; $sum_hum / $n" | bc) %"
echo "Día más caluroso : $dia_caluroso ($t_caluroso ºC)"
echo "Día más frío : $dia_frio ($t_frio ºC)"
echo "Día con mayor amplitud : $dia_amplitud ($amplitud_max ºC)"
#!/bin/bash
awk '{
sum_min += $2
sum_max += $3
sum_hum += $4
if ($3 > t_caluroso) { t_caluroso = $3 ; dia_caluroso = $1 }
if (NR == 1 || $2 < t_frio) { t_frio = $2 ; dia_frio = $1 }
if ($3 - $2 > amplitud_max) { amplitud_max = $3 - $2 ; dia_amplitud = $1 }
}
END {
printf "Temperatura mínima media : %.1f ºC\n", sum_min/NR
printf "Temperatura máxima media : %.1f ºC\n", sum_max/NR
printf "Humedad media : %.1f %%\n", sum_hum/NR
print "Día más caluroso : " dia_caluroso " (" t_caluroso " ºC)"
print "Día más frío : " dia_frio " (" t_frio " ºC)"
print "Día con mayor amplitud : " dia_amplitud " (" amplitud_max " ºC)"
}' meteo.dat
#!/bin/bash
archivo="meteo.dat"
dia=()
tmin=()
tmax=()
hum=()
while read d min max h
do
dia+=($d)
tmin+=($min)
tmax+=($max)
hum+=($h)
done < $archivo
n=${#dia[@]}
sum_min=0
sum_max=0
sum_hum=0
imax=0 # índice del día más caluroso
imin=0 # índice del día más frío
iamp=0 # índice del día con mayor amplitud
for((i=0;i<$n;i++))
do
sum_min=$(echo "$sum_min + ${tmin[$i]}" | bc -l)
sum_max=$(echo "$sum_max + ${tmax[$i]}" | bc -l)
sum_hum=$(echo "$sum_hum + ${hum[$i]}" | bc -l)
# con decimales no podemos usar -gt o -lt, comparamos con bc
if [ $(echo "${tmax[$i]} > ${tmax[$imax]}" | bc -l) -eq 1 ]; then imax=$i ; fi
if [ $(echo "${tmin[$i]} < ${tmin[$imin]}" | bc -l) -eq 1 ]; then imin=$i ; fi
amplitud=$(echo "${tmax[$i]} - ${tmin[$i]}" | bc -l)
amplitud_max=$(echo "${tmax[$iamp]} - ${tmin[$iamp]}" | bc -l)
if [ $(echo "$amplitud > $amplitud_max" | bc -l) -eq 1 ]; then iamp=$i ; fi
done
echo "Temperatura mínima media : $(echo "scale=1; $sum_min / $n" | bc) ºC"
echo "Temperatura máxima media : $(echo "scale=1; $sum_max / $n" | bc) ºC"
echo "Humedad media : $(echo "scale=1; $sum_hum / $n" | bc) %"
echo "Día más caluroso : ${dia[$imax]} (${tmax[$imax]} ºC)"
echo "Día más frío : ${dia[$imin]} (${tmin[$imin]} ºC)"
echo "Día con mayor amplitud : ${dia[$iamp]} ($(echo "${tmax[$iamp]} - ${tmin[$iamp]}" | bc) ºC)"
alerta_disco.sh#
Crea un script llamado alerta_disco.sh que recorra las particiones montadas y, por cada una que supere un umbral de ocupación, escriba una alerta con la fecha en el archivo alertas.log y también por pantalla. El umbral se recibe como argumento, por defecto será 80.
./alerta_disco.sh 50
2026-07-07 10:30 / está al 57% (umbral 50%)
cat alertas.log
2026-07-07 10:30 / está al 57% (umbral 50%)
Consejos:
df | tail -n +2quita la línea de cabecera, y como en meteo.sh puedes leer las columnas conwhile read.tr -d '%'elimina el símbolo % para poder comparar con-ge.tee -aescribe a la vez por pantalla y al final de un archivo.
#!/bin/bash
umbral=${1:-80} # umbral en %, por defecto 80
log="alertas.log"
df | tail -n +2 | tr -s ' ' | while read particion bloques usado disponible pcent montaje
do
ocupado=$(echo $pcent | tr -d '%')
if [ $ocupado -ge $umbral ]
then
echo "$(date '+%F %H:%M') $montaje está al $ocupado% (umbral $umbral%)" | tee -a $log
fi
done
rnd.sh#
Haz un script llamado rnd.sh que muestre 5 números aleatorios del 1 al 10 seguidos de el mismo número de As,
1 A
3 AAA
1 A
6 AAAAAA
2 AA
Haz que el reciba como argumento de entrada en numero de intentos, es decir ./rnd.sh 5
En el caso de no recibir ningún numero haz que saque 5
#!/bin/bash
n=${1:-5}
for (( i = 0 ; i < n ; i++ ))
do
x=$((RANDOM % 10 + 1))' '
out=$x' '
for (( j=0 ; j<x ; j++ ))
do
out=${out}A
done
echo $out
done
#!/bin/bash
n=${1:-5}
for (( i = 0 ; i < n ; i++ ))
do
x=$((RANDOM % 10 + 1))' '
A[$i]=$x' '
for (( j=0 ; j<x ; j++ ))
do
A[$i]=${A[$i]}A
done
done
for (( i = 0 ; i < n ; i++ ))
do
echo ${A[$i]}
done
adivina.sh#
Crea un script llamado adivina.sh que escoja un numero aleatorio entre 1 y 20, pregunte al usuario, le diga si es más pequeño o más grande y que continué hasta que acierte.
Cuando el usuario acierte haz que muestre el número de intentos.
#!/bin/bash
# Generar un número aleatorio entre 1 y 20
numero_secreto=$((RANDOM % 20 + 1))
echo $numero_secreto
intentos=0
echo "¡Adivina el número entre 1 y 20!"
acertado=0
while [[ $acertado == 0 ]]
do
intentos=$((intentos+1))
read -p "Introduce tu número: " respuesta
# Comparar el número ingresado con el número secreto
if [[ $respuesta -lt $numero_secreto ]]; then
echo "El número es más grande."
elif [[ $respuesta -gt $numero_secreto ]]; then
echo "El número es más pequeño."
else
echo "¡Correcto! El número era $numero_secreto."
echo "Lo has adivinado en $intentos intento(s)."
acertado=1
fi
done
contar_monedas.sh#
Crea un script llamado contar_monedas.sh que lea el número de monedas que hay de un archivo llamado monedas.dat.
Genera el archivo monedas.dat utilizando el siguiente codigo:
for((i=0;i<10;i++))
do
echo $((RANDOM%10))
done > monedas.dat
#!/bin/bash
x1=0
x2=0
x3=0
x4=0
x5=0
x6=0
x7=0
x8=0
x9=0
total=0
for((i=0;i<1000;i++))
do
x=$(head -$i monedas.dat | tail -1 )
total=$((total+x))
if [[ $x -eq 1 ]]; then x1=$((x1+1)); fi
if [[ $x -eq 2 ]]; then x2=$((x2+1)); fi
if [[ $x -eq 3 ]]; then x3=$((x3+1)); fi
if [[ $x -eq 4 ]]; then x4=$((x4+1)); fi
if [[ $x -eq 5 ]]; then x5=$((x5+1)); fi
if [[ $x -eq 6 ]]; then x6=$((x6+1)); fi
if [[ $x -eq 7 ]]; then x7=$((x7+1)); fi
if [[ $x -eq 8 ]]; then x8=$((x8+1)); fi
if [[ $x -eq 9 ]]; then x9=$((x9+1)); fi
done
echo hay $x1 con 1 euros
echo hay $x2 con 2 euros
echo hay $x3 con 3 euros
echo hay $x4 con 4 euros
echo hay $x5 con 5 euros
echo hay $x6 con 6 euros
echo hay $x7 con 7 euros
echo hay $x8 con 8 euros
echo hay $x9 con 9 euros
echo hay $total de dinero
#!/bin/bash
for((i=0;i<10;i++))
do
x[$i]=0
done
total=0
for((i=1;i<$(wc -l monedas.dat | cut -d' ' -f1);i++))
do
monedas=$(head -$i monedas.dat | tail -1 )
total=$((total+monedas))
for((j=0;j<10;j++))
do
if [[ $monedas -eq $j ]]
then
x[$j]=$((x[$j]+1))
fi
done
done
for((i=0;i<10;i++))
do
echo hay ${x[$i]} con $i euros
done
echo hay $total de dinero
piedra_papel_tijera.sh#
Crea un script en Bash llamado piedra_papel_tijera.sh que simule el juego de (Piedra, Papel o Tijera) entre dos jugadores durante un número dado de partidas.
Cada jugador debe elegir aleatoriamente entre piedra, papel o tijera. El programa deberá contar cuántas veces gana el Jugador 1, cuántas gana el Jugador 2 y cuántas veces empatan.
La salida debe ser un resumen con los porcentajes de empate, victoria del Jugador 1 y victoria del Jugador 2, con dos cifras decimales de precisión.
Una vez creado el script, muestra los resultados, como sigue:
for i in 10 50 100 1000 10000 100000;
do
echo $i $(./piedra_papel_tijera.sh $i)
done
10 Empate = 40.00 %, Gana 1 = 40.00 %, Gana 2 = 20.00 %
50 Empate = 36.00 %, Gana 1 = 46.00 %, Gana 2 = 18.00 %
100 Empate = 31.00 %, Gana 1 = 32.00 %, Gana 2 = 37.00 %
1000 Empate = 34.30 %, Gana 1 = 34.40 %, Gana 2 = 31.30 %
10000 Empate = 33.75 %, Gana 1 = 33.01 %, Gana 2 = 33.24 %
100000 Empate = 33.30 %, Gana 1 = 33.24 %, Gana 2 = 33.44 %
#!/bin/bash
opcion=( "piedra" "papel" "tijera" )
contador_gana1=0
contador_gana2=0
contador_empate=0
n_turnos=${1:-10}
for (( i=1; i<=n_turnos; i++ ))
do
jugador1=${opcion[$(($RANDOM % 3))]}
jugador2=${opcion[$(($RANDOM % 3))]}
#echo "$jugador1, $jugador2"
#Empates
if [ $jugador1 == $jugador2 ]
then
contador_empate=$(($contador_empate+1))
fi
#Gana 1
if [ $jugador1 == "piedra" ] && [ $jugador2 == "tijera" ]
then
contador_gana1=$(($contador_gana1+1))
fi
if [ $jugador1 == "papel" ] && [ $jugador2 == "piedra" ]
then
contador_gana1=$(($contador_gana1+1))
fi
if [ $jugador1 == "tijera" ] && [ $jugador2 == "papel" ]
then
contador_gana1=$(($contador_gana1+1))
fi
#Gana 2
if [ $jugador2 == "piedra" ] && [ $jugador1 == "tijera" ]
then
contador_gana2=$(($contador_gana2+1))
fi
if [ $jugador2 == "papel" ] && [ $jugador1 == "piedra" ]
then
contador_gana2=$(($contador_gana2+1))
fi
if [ $jugador2 == "tijera" ] && [ $jugador1 == "papel" ]
then
contador_gana2=$(($contador_gana2+1))
fi
done
#echo "$contador_empate, $contador_gana1, $contador_gana2"
port_empate=$(echo "scale=2 ; $contador_empate*100/$n_turnos" | bc -l)
port_gana1=$(echo "scale=2 ; $contador_gana1*100/$n_turnos" | bc -l)
port_gana2=$(echo "scale=2 ; $contador_gana2*100/$n_turnos" | bc -l)
echo "Empate = $port_empate %, Gana 1 = $port_gana1 %, Gana 2 = $port_gana2"
notas.sh#
Haz un script llamado notas.sh que a partir de un fichero donde se recogen las calificaciones de los alumnos en los distintos módulos denominado calificaciones.txt con el siguiente formato:
Lucía Sánchez: 10, 6, 6, 5, 8
María Vargas: 9, 7, 4, 4, 7
Lucía Pérez: 7, 5, 10, 8, 4
Miguel González: 9, 7, 10, 3, 5
Miguel López: 6, 4, 6, 10, 9
Elena García: 3, 3, 3, 10, 4
Pedro Torres: 6, 4, 10, 9, 4
Se pide:
El número de alumnos matriculados.
El número de alumnos que han aprobado todos los módulos.
El número de alumnos que han suspendido sólo un módulo.
El número de alumnos que han suspendido dos módulos.
El número de alumnos que han suspendido tres módulos o más.
Indicar el número de alumnos aprobados/suspensos en porcentaje.
#!/bin/bash
archivo="calificaciones.txt"
todos_aprobados=0
un_suspenso=0
dos_suspensos=0
tres_o_mas_suspensos=0
num_alumnos=$(wc -l $archivo | cut -d' ' -f1)
for ((i=1; i<=num_alumnos; i++))
do
linea=$(sed -n ${i}p $archivo)
aprobado_1=0
aprobado_2=0
aprobado_3=0
aprobado_4=0
aprobado_5=0
nota_1=$(echo $linea |cut -d':' -f2|cut -d',' -f1)
if [ $nota_1 -ge 5 ]; then aprobado_1=1 ; fi
nota_2=$(echo $linea |cut -d':' -f2|cut -d',' -f2)
if [ $nota_2 -ge 5 ]; then aprobado_2=1 ; fi
nota_3=$(echo $linea |cut -d':' -f2|cut -d',' -f3)
if [ $nota_3 -ge 5 ]; then aprobado_3=1 ; fi
nota_4=$(echo $linea |cut -d':' -f2|cut -d',' -f4)
if [ $nota_4 -ge 5 ]; then aprobado_4=1 ; fi
nota_5=$(echo $linea |cut -d':' -f2|cut -d',' -f5)
if [ $nota_5 -ge 5 ]; then aprobado_5=1 ; fi
sum_aprobados=$((aprobado_1 + aprobado_2 + aprobado_3 + aprobado_4 + aprobado_5))
if [ $sum_aprobados -eq 5 ]; then todos_aprobados=$((todos_aprobados+1)) ; fi
if [ $sum_aprobados -eq 4 ]; then un_suspenso=$((un_suspenso+1)) ; fi
if [ $sum_aprobados -eq 3 ]; then dos_suspensos=$((dos_suspensos+1)) ; fi
if [ $sum_aprobados -lt 3 ]; then tres_o_mas_suspensos=$((tres_o_mas_suspensos+1)) ; fi
echo -e "$linea : \033[32m$sum_aprobados \033[0mmod. aprobados "
done
porcentaje_aprobados=$(echo "scale=2; ($todos_aprobados / $num_alumnos) * 100" | bc)
porcentaje_suspensos=$(echo "scale=2; (($num_alumnos-$todos_aprobados) / $num_alumnos) * 100" | bc)
echo -e "\033[34m-------------- Resultados ---------------- \033[0m"
echo -e "Número total de alumnos matriculados:\033[32m $num_alumnos \033[0m"
echo -e "Número de alumnos que han aprobado todos los módulos:\033[32m $todos_aprobados\033[0m"
echo -e "Número de alumnos que han suspendido solo un módulo:\033[32m $un_suspenso\033[0m"
echo -e "Número de alumnos que han suspendido dos módulos:\033[32m $dos_suspensos\033[0m"
echo -e "Número de alumnos que han suspendido tres módulos o más:\033[32m $tres_o_mas_suspensos\033[0m"
echo -e "Porcentaje de alumnos aprobados:\033[35m $porcentaje_aprobados %\033[0m"
echo -e "Porcentaje de alumnos suspensos:\033[35m $porcentaje_suspensos %\033[0m"
#!/bin/bash
# Verificar que el archivo existe
if [ ! -f "calificaciones.txt" ]; then
echo "Error: El archivo calificaciones.txt no existe en el directorio actual."
exit 1
fi
# Verificar que el archivo no está vacío
if [ ! -s "calificaciones.txt" ]; then
echo "Error: El archivo calificaciones.txt está vacío."
exit 1
fi
# Procesar con awk
awk -F'[:,]' '
BEGIN {
print "============================================="
print " ESTADÍSTICAS DE CALIFICACIONES"
print "=============================================\n"
# Inicializar contadores
total = 0
aprob_todos = 0
un_suspenso = 0
dos_suspensos = 0
tres_o_mas = 0
aprob_general = 0
susp_general = 0
}
{
total++
suspensos = 0
# Contar suspensos (notas < 5)
for(i=2; i<=NF; i++) {
# Convertir a número (el +0 elimina espacios automáticamente)
nota = $i + 0
if (nota < 5) suspensos++
}
# Contar por categorías
if (suspensos == 0) aprob_todos++
if (suspensos == 1) un_suspenso++
if (suspensos == 2) dos_suspensos++
if (suspensos >= 3) tres_o_mas++
# Contar aprobados generales (<= 2 suspensos)
if (suspensos <= 2) {
aprob_general++
} else {
susp_general++
}
}
END {
print "1. Número de alumnos matriculados: " total
print "2. Alumnos que han aprobado todos los módulos: " aprob_todos
print "3. Alumnos que han suspendido sólo un módulo: " un_suspenso
print "4. Alumnos que han suspendido dos módulos: " dos_suspensos
print "5. Alumnos que han suspendido tres módulos o más: " tres_o_mas
printf "\n6. Porcentaje de alumnos:\n"
printf " Aprobados (<= 2 suspensos): %.2f%%\n", (aprob_general/total)*100
printf " Suspensos (> 2 suspensos): %.2f%%\n", (susp_general/total)*100
print "\n============================================="
}' calificaciones.txt
Ahora las calificaciones están en formato csv con cabecera, en el archivo calificaciones.csv:
nombre,mod1,mod2,mod3,mod4,mod5
Lucía Sánchez,10,6,6,5,8
María Vargas,9,7,4,4,7
Fíjate que al separar los campos con IFS=',' y read el script se simplifica: cada nota llega a una variable sin necesidad de cut.
#!/bin/bash
archivo="calificaciones.csv"
num_alumnos=0
todos_aprobados=0
un_suspenso=0
dos_suspensos=0
tres_o_mas_suspensos=0
while IFS=',' read -r nombre nota_1 nota_2 nota_3 nota_4 nota_5
do
if [[ $nombre == "nombre" ]]; then continue; fi # saltamos la cabecera
num_alumnos=$((num_alumnos+1))
sum_aprobados=0
for nota in $nota_1 $nota_2 $nota_3 $nota_4 $nota_5
do
if [ $nota -ge 5 ]; then sum_aprobados=$((sum_aprobados+1)); fi
done
if [ $sum_aprobados -eq 5 ]; then todos_aprobados=$((todos_aprobados+1)) ; fi
if [ $sum_aprobados -eq 4 ]; then un_suspenso=$((un_suspenso+1)) ; fi
if [ $sum_aprobados -eq 3 ]; then dos_suspensos=$((dos_suspensos+1)) ; fi
if [ $sum_aprobados -lt 3 ]; then tres_o_mas_suspensos=$((tres_o_mas_suspensos+1)) ; fi
echo -e "$nombre: $nota_1, $nota_2, $nota_3, $nota_4, $nota_5 : \033[32m$sum_aprobados \033[0mmod. aprobados "
done < $archivo
porcentaje_aprobados=$(echo "scale=2; ($todos_aprobados / $num_alumnos) * 100" | bc)
porcentaje_suspensos=$(echo "scale=2; (($num_alumnos-$todos_aprobados) / $num_alumnos) * 100" | bc)
echo -e "\033[34m-------------- Resultados ---------------- \033[0m"
echo -e "Número total de alumnos matriculados:\033[32m $num_alumnos \033[0m"
echo -e "Número de alumnos que han aprobado todos los módulos:\033[32m $todos_aprobados\033[0m"
echo -e "Número de alumnos que han suspendido solo un módulo:\033[32m $un_suspenso\033[0m"
echo -e "Número de alumnos que han suspendido dos módulos:\033[32m $dos_suspensos\033[0m"
echo -e "Número de alumnos que han suspendido tres módulos o más:\033[32m $tres_o_mas_suspensos\033[0m"
echo -e "Porcentaje de alumnos aprobados:\033[35m $porcentaje_aprobados %\033[0m"
echo -e "Porcentaje de alumnos suspensos:\033[35m $porcentaje_suspensos %\033[0m"
analizar_cal.sh#
Descarga el archivo calendario.dat, encontrará 543 citas donde el primer campo es el mes, el segundo campo es el día, el tercer campo es la hora y el cuarto la cita
Crea un script llamado analizar_cal.sh que considere las siguientes entradas:
Muestra un mensaje de ayuda
./analizar_cal.sh --help salida: Uso : analizar [OPCION] Options: - mes <mes> muestra el número de citas que hay en un mes - d <día> muestra el numero de citas que hay para ese día para todos los meses
En el caso de no dar ninguna entrada también mostrará el mensaje de ayuda
Muestra el número de citas que hay por mes
./analizar_cal.sh -mes Julio 39
Muestra el número de citas que hay por un determinado día para todos los meses
./analizar_cal.sh -d 4 11
Muestra el número de citas que se han producido durante todo el año de forma ordenada
./analizar_cal.sh -resumen citas | head 23 Reunión de trabajo. 16 Cita con el médico. 14 Llamada con un cliente. 14 Entrega de proyectos. 14 Cumpleaños de un amigo. 14 Clase de yoga o ejercicio. 14 Cena con amigos. 14 Aniversario de boda. 13 Conferencia o seminario. 10 Visita al dentista.
Muestra el numero de citas que hay por diferentes franjas horarias
./analizar_cal.sh -resumen horas De 10:00-10:59 hay 87 citas De 11:00-10:59 hay 80 citas De 12:00-10:59 hay 99 citas De 13:00-10:59 hay 97 citas De 14:00-10:59 hay 79 citas De 15:00-10:59 hay 101 citas
#!/bin/bash
function show_help() {
echo "Uso : analizar [OPCION]"
echo "Options:"
echo "- mes <mes> muestra el numero de citas que hay en un mes"
echo "- d <dia> muestra el numero de citas que hay para ese dia para todos los meses"
}
archivo=calendario.dat
if [[ $# -gt 0 ]]
then
if [[ $1 == "--help" ]]
then
show_help
fi
if [[ $1 == "-mes" ]]
then
grep -c $2 $archivo
fi
if [[ $1 == "-d" ]]
then
cat $archivo | grep -c " $2 "
fi
if [[ $1 == "-resumen" ]]
then
if [[ $2 == citas ]]
then
cat $archivo | tr -s ' ' | cut -d' ' -f4- | sort | uniq -c | sort -r
fi
if [[ $2 == horas ]]
then
hora=$(cat $archivo | tr -s ' ' | cut -d' ' -f3 | cut -d':' -f1 | sort | uniq -c | tr -s ' '| cut -d' ' -f3)
c=0
for i in $hora
do
c=$((c+1))
cita=$(cat $archivo | tr -s ' ' | cut -d' ' -f3 | cut -d':' -f1 | sort | uniq -c | tr -s ' '| grep $i | cut -d' ' -f2 | head -$c | tail -1)
echo De $i:00-10:59 hay $cita citas
done
fi
fi
else
show_help
fi
analizar_web.sh#
Crea un script llamado analizar_web.sh que analice el registro de accesos de un servidor Apache (access.log). Si no recibe ningún archivo usará /var/log/apache2/access.log, y si el archivo no existe mostrará un error.
Para generar tu propio log, arranca Apache (tema Apache) y visita varias veces tu servidor desde el navegador, incluyendo alguna página que no exista (para provocar errores 404).
El script debe mostrar:
El número total de peticiones.
Las 5 IPs que más veces han conectado.
Las 5 URLs más pedidas.
El recuento de códigos de respuesta (200, 404, 302...).
Las páginas que dan 404.
El número de peticiones por hora.
./analizar_web.sh access.log
=== Análisis de access.log (7 peticiones) ===
--- Top 5 IPs ---
4 10.0.0.1
2 10.0.0.2
1 10.0.0.3
...
Es la culminación de la cadena sort | uniq -c | sort -rn que empezó en rep.sh: en el formato común de Apache el campo 1 es la IP, el 7 la URL y el 9 el código de respuesta (cut -d' '), y para las 404 y la hora conviene usar awk.
#!/bin/bash
# analizar_web.sh - análisis del access.log de Apache
archivo=${1:-/var/log/apache2/access.log}
if [ ! -f "$archivo" ]; then
echo -e "\033[31mNo existe el archivo $archivo\033[0m"
echo "Uso: ./analizar_web.sh [access.log]"
exit 1
fi
total=$(wc -l < "$archivo")
echo -e "\033[34m=== Análisis de $archivo ($total peticiones) ===\033[0m"
# En el formato común de Apache el campo 1 es la IP, el 7 la URL y el 9 el código
echo -e "\n--- Top 5 IPs ---"
cut -d' ' -f1 "$archivo" | sort | uniq -c | sort -rn | head -5
echo -e "\n--- Top 5 URLs ---"
cut -d' ' -f7 "$archivo" | sort | uniq -c | sort -rn | head -5
echo -e "\n--- Códigos de respuesta ---"
cut -d' ' -f9 "$archivo" | sort | uniq -c | sort -rn
echo -e "\n--- Páginas no encontradas (404) ---"
awk '$9 == 404 {print $7}' "$archivo" | sort | uniq -c | sort -rn | head -5
echo -e "\n--- Peticiones por hora ---"
# la fecha va como [10/Oct/2024:13:55:36 ...], nos quedamos con la hora
awk -F'[:[]' '{print $3":00"}' "$archivo" | sort | uniq -c
rep.sh#
Crea un script llamado rep.sh que diga el número de veces que están repetidos los siguientes nombres del archivo nombres.dat
#!/bin/bash
sort nombres.dat | uniq -c | sort -nr
nlineas=$(wc -l nombres.dat | cut -d' ' -f1)
for((i=1;i<=$nlineas;i++))
do
A[$i]=$(head -$i nombres.dat | tail -1)
done
count=0
for((i=1;i<=$nlineas;i++))
do
encontrado=0
for((j=1;j<=${#B[@]};j++))
do
if [ ${B[j]} == ${A[i]} ]
then
encontrado=1
fi
done
if [[ $encontrado -eq 0 ]]
then
count=$((count+1))
B[$count]=${A[i]}
fi
done
for((i=1;i<=${#B[@]};i++))
do
C[$i]=0
for((j=1;j<=${#A[@]};j++))
do
if [ ${B[i]} == ${A[j]} ]
then
C[$i]=$((${C[i]}+1))
fi
done
done
for((i=1;i<=${#B[@]};i++))
do
echo "${C[i]} ${B[i]}"
done | sort -rn
duplicados.sh#
Crea un script llamado duplicados.sh que encuentre los archivos con el mismo contenido dentro de un directorio (aunque tengan nombres distintos), agrupándolos. Si no recibe el directorio como argumento analizará el directorio actual.
Para probarlo genera unos archivos con duplicados:
mkdir ficheros
for i in 1 2 3; do echo "contenido $i" > ficheros/original_$i.txt; done
cp ficheros/original_1.txt ficheros/copia_1.txt
cp ficheros/original_1.txt ficheros/otra_copia.txt
cp ficheros/original_2.txt ficheros/copia_2.txt
./duplicados.sh ficheros
Duplicados:
ficheros/copia_1.txt
ficheros/original_1.txt
ficheros/otra_copia.txt
Duplicados:
ficheros/copia_2.txt
ficheros/original_2.txt
Consejos:
md5sumcalcula un hash del contenido: dos archivos con el mismo contenido tienen el mismo hash, se llamen como se llamen.find <dir> -type f -exec md5sum {} \;calcula el hash de todos los archivos, y consort | uniq -dsobre la columna del hash tienes los repetidos (la misma cadena que en rep.sh).$$es el PID del script, útil para crear un archivo temporal (/tmp/hashes.$$) que no pise el de otra ejecución.
#!/bin/bash
dir=${1:-.} # directorio a analizar, por defecto el actual
hashes=/tmp/hashes.$$ # $$ es el PID, evita pisar el archivo de otra ejecución
find $dir -type f -exec md5sum {} \; | sort > $hashes
for hash in $(cut -d' ' -f1 $hashes | uniq -d)
do
echo "Duplicados:"
grep "^$hash" $hashes | tr -s ' ' | cut -d' ' -f2
done
rm $hashes
monedas.sh#
Sube al curso un script llamado monedas.sh que tire tres monedas y escriba en un archivo el resultado.
Haz que lea el archivo y obtenga el porcentaje de veces que salen 3 caras.
En el caso de que no se proporcione el número de tiradas ni el archivo, tomara por defecto el archivo llamado tiradas.dat y hará 100 tiradas.
En el caso de que no encuentre el archivo cuando lo va a leer, tomara por defecto monedas.dat, si este no existe, mostrará que no existe.
$ ./monedas.sh -help
-n <tiradas> <archivo>
-read <archivo>
#!/bin/bash
function show_help() {
echo -e "\033[32m -help\033[0m"
echo -e "\033[32m -n <tiradas> <archivo> \033[0m"
echo -e "\033[32m -read <archivo> \033[0m"
}
if [[ $1 == '-help' ]]
then
show_help
fi
if [[ $1 == '-n' ]]
then
tiradas=${2:-100}
outfile=${3:-monedas.dat}
for((i=0;i<$tiradas;i++))
do
echo $((RANDOM % 2)) $((RANDOM % 2)) $((RANDOM % 2))
done > $outfile
fi
if [[ $1 == '-read' ]]
then
readfile=${2:-monedas.dat}
if test -f $readfile
then
echo -e "\033[32m Leemos el archivo $readfile \033[0m"
tres_caras=$(grep -c '1 1 1' $readfile)
n_total=$(wc -l $readfile | cut -d ' ' -f1)
echo -e "\033[33m Tenemos $((tres_caras * 100 / n_total))% de tiradas con tres caras \033[0m"
else
echo -e "\033[31m El archivo $readfile no existe\033[0m"
fi
fi
ip.sh#
Crea un script en Bash llamado ips.sh que cumpla con los siguientes requisitos:
Si ejecutas el script con ./ips.sh -help, debe mostrar la siguiente ayuda:
-help : muestra la ayuda
-file <archivo> <número_ips> : Crea un archivo llamado <archivo> con <número_ips>.
-find <archivo> <ip> : Muestra cuantas veces aparece la <ip>
-read <archivo> : Muestra de forma ordenada las IPs por número de conexiones
Si ejecutas el script sin argumentos ./ips.sh, también debe mostrar la ayuda.
Si ejecutas el ./ips.sh -file sin indicar el <número_ips> tomara por defecto 50, en el caso de no darle el <archivo> tomará por defecto ip.dat. Cada línea tendrá una IP aleatoria dentro del rango 192.168.2.0/28. La primera IP utilizable es 192.168.2.1 y la última es 192.168.2.14.
Si ejecutas el ./ips.sh -find lee el <archivo>, si no existe o no se le indica, mostrará por pantalla "El archivo no existe", en el caso de que no se proporcione <ip> mostrará por pantalla "Proporcionar ip"
Si ejecutas el ./ips.sh -read lee el <archivo>, si no existe o no se le indica, mostrará por pantalla "El archivo no existe"
#!/bin/bash
function show_help() {
echo -e "\033[32m-help : muestra la ayuda\033[0m"
echo -e "\033[32m-file <archivo> <número_ips> : Crea un archivo llamado <archivo> con <número_ips> \033[0m"
echo -e "\033[32m-find <archivo> <ip> : Muestra cuantas veces aparece la <ip> \033[0m"
echo -e "\033[32m-read <archivo> : Muestra de forma ordenada las IPs por número de conexiones \033[0m"
}
if [[ $1 == '-help' ]]
then
show_help
fi
if [[ $# -eq 0 ]]
then
show_help
fi
if [[ $1 == '-file' ]]
then
tiradas=${3:-50}
outfile=${2:-ip.dat}
for((i=0;i<$tiradas;i++))
do
echo 192.168.2.$((RANDOM % 14 + 1))
done > $outfile
fi
if [[ $1 == '-find' ]]
then
readfile=$2
ip=$3
if test -z $3
then
echo -e "\033[31m Proporcionar ip\033[0m"
else
if test -f $readfile
then
echo -e "\033[32m Leemos el archivo $readfile \033[0m"
grep -c $ip $readfile
else
echo -e "\033[31m El archivo $readfile no existe\033[0m"
fi
fi
fi
if [[ $1 == '-read' ]]
then
readfile=$2
if test -f $readfile
then
echo -e "\033[32m Leemos el archivo $readfile \033[0m"
cat $readfile | sort | uniq -c | sort -rn
else
echo -e "\033[31m El archivo $readfile no existe\033[0m"
fi
fi
Puedes probar todas las opciones con el script uso_ip.sh, la función run imprime el comando antes de ejecutarlo (fíjate en el uso de "$@"):
#!/bin/bash
# Prueba todas las opciones de ip.sh
function run() {
echo ""
echo -e "\033[33m### $* \033[0m"
"$@"
}
run ./ip.sh -help
run ./ip.sh -file conexiones.dat 30
run ./ip.sh -read conexiones.dat
run ./ip.sh -find conexiones.dat 192.168.2.13
run ./ip.sh -find conexiones.dat
run ./ip.sh -find noexiste.dat 192.168.2.13
run ./ip.sh -read noexiste.dat
run ./ip.sh
inventario.sh#
Crea un script en Bash llamado inventario.sh que gestione un inventario de equipos en formato CSV. Cada línea del archivo tendrá los campos hostname,ip,ram_gb,estado, y la primera línea será la cabecera:
hostname,ip,ram_gb,estado
pc-01,192.168.1.54,4,mantenimiento
pc-02,192.168.1.95,4,activo
pc-03,192.168.1.17,64,activo
Si ejecutas el script con ./inventario.sh -help, debe mostrar la siguiente ayuda:
-help : muestra la ayuda
-crear <archivo> <N> : Crea un csv con N equipos
-add <archivo> <hostname> <ip> <ram> <estado>: Añade un equipo al csv
-find <archivo> <hostname> : Muestra la información del equipo
-del <archivo> <hostname> : Borra el equipo del csv
-read <archivo> : Muestra el inventario en forma de tabla
-resumen <archivo> : Muestra un resumen del inventario
Si ejecutas el script sin argumentos
./inventario.sh, también debe mostrar la ayuda.Si ejecutas
./inventario.sh -crearsin indicar<N>tomará por defecto 20 equipos, en el caso de no darle el<archivo>tomará por defecto inventario.csv. Los hostname serán pc-01, pc-02..., la IP será aleatoria dentro de 192.168.1.0/24, la RAM se escogerá aleatoriamente entre 4, 8, 16, 32 y 64 GB, y el estado entre activo, apagado y mantenimiento.Si ejecutas
./inventario.sh -addañadirá una línea al final del archivo, si el archivo no existe o faltan campos mostrará un mensaje de error.Si ejecutas
./inventario.sh -findbuscará el equipo por su hostname y mostrará sus campos uno por línea (consejo: utilizaIFS=','conread):./inventario.sh -find inventario.csv pc-03 hostname: pc-03 ip : 192.168.1.17 ram : 64 GB estado : activo
Si ejecutas
./inventario.sh -delborrará la línea del equipo indicado, si el equipo no existe mostrará "No se encuentra el equipo" (consejo: utilizased -icon la dirección/^<hostname>,/d).Si ejecutas
./inventario.sh -readmostrará el inventario alineado en columnas (consejo: miraman column).Si ejecutas
./inventario.sh -resumenmostrará el número de equipos, la RAM total y el número de equipos por estado (consejo: utilizaawk -F','saltando la cabecera conNR>1):./inventario.sh -resumen inventario.csv Equipos : 20 RAM total : 484 GB mantenimiento : 4 apagado : 6 activo : 10
En todas las opciones que leen el archivo, si este no existe mostrará "El archivo no existe".
#!/bin/bash
function show_help() {
echo -e "\033[32m-help : muestra la ayuda\033[0m"
echo -e "\033[32m-crear <archivo> <N> : Crea un csv con N equipos\033[0m"
echo -e "\033[32m-add <archivo> <hostname> <ip> <ram> <estado>: Añade un equipo al csv\033[0m"
echo -e "\033[32m-find <archivo> <hostname> : Muestra la información del equipo\033[0m"
echo -e "\033[32m-del <archivo> <hostname> : Borra el equipo del csv\033[0m"
echo -e "\033[32m-read <archivo> : Muestra el inventario en forma de tabla\033[0m"
echo -e "\033[32m-resumen <archivo> : Muestra un resumen del inventario\033[0m"
}
if [[ $1 == '-help' ]]
then
show_help
fi
if [[ $# -eq 0 ]]
then
show_help
fi
if [[ $1 == '-crear' ]]
then
outfile=${2:-inventario.csv}
n=${3:-20}
ram=(4 8 16 32 64)
estado=(activo apagado mantenimiento)
echo "hostname,ip,ram_gb,estado" > $outfile
for((i=1;i<=$n;i++))
do
printf "pc-%02d,192.168.1.%d,%d,%s\n" $i $((RANDOM % 254 + 1)) ${ram[$((RANDOM % 5))]} ${estado[$((RANDOM % 3))]}
done >> $outfile
echo -e "\033[32m Creado $outfile con $n equipos \033[0m"
fi
if [[ $1 == '-add' ]]
then
readfile=$2
if test -f $readfile
then
if [[ $# -lt 6 ]]
then
echo -e "\033[31m Faltan campos: -add <archivo> <hostname> <ip> <ram> <estado>\033[0m"
else
echo "$3,$4,$5,$6" >> $readfile
echo -e "\033[32m Añadido $3 a $readfile \033[0m"
fi
else
echo -e "\033[31m El archivo $readfile no existe\033[0m"
fi
fi
if [[ $1 == '-find' ]]
then
readfile=$2
if test -z $3
then
echo -e "\033[31m Proporcionar hostname\033[0m"
else
if test -f $readfile
then
linea=$(grep "^$3," $readfile)
if test -z $linea
then
echo -e "\033[31m No se encuentra el equipo $3\033[0m"
else
echo $linea | while IFS=',' read hostname ip ram estado
do
echo -e "\033[32m hostname: $hostname\033[0m"
echo -e "\033[32m ip : $ip\033[0m"
echo -e "\033[32m ram : $ram GB\033[0m"
echo -e "\033[32m estado : $estado\033[0m"
done
fi
else
echo -e "\033[31m El archivo $readfile no existe\033[0m"
fi
fi
fi
if [[ $1 == '-del' ]]
then
readfile=$2
if test -z $3
then
echo -e "\033[31m Proporcionar hostname\033[0m"
else
if test -f $readfile
then
if grep -q "^$3," $readfile
then
sed -i "/^$3,/d" $readfile
echo -e "\033[32m Borrado $3 de $readfile \033[0m"
else
echo -e "\033[31m No se encuentra el equipo $3\033[0m"
fi
else
echo -e "\033[31m El archivo $readfile no existe\033[0m"
fi
fi
fi
if [[ $1 == '-read' ]]
then
readfile=$2
if test -f $readfile
then
echo -e "\033[32m Leemos el archivo $readfile \033[0m"
column -t -s',' $readfile
else
echo -e "\033[31m El archivo $readfile no existe\033[0m"
fi
fi
if [[ $1 == '-resumen' ]]
then
readfile=$2
if test -f $readfile
then
awk -F',' 'NR>1 {
n++
ram+=$3
estado[$4]++
}
END {
print "Equipos :", n
print "RAM total :", ram, "GB"
for (e in estado) print e, ":", estado[e]
}' $readfile
else
echo -e "\033[31m El archivo $readfile no existe\033[0m"
fi
fi
Puedes probar todas las opciones con el script uso_inventario.sh, la función run imprime el comando antes de ejecutarlo (fíjate en el uso de "$@"):
#!/bin/bash
# Prueba todas las opciones de inventario.sh
function run() {
echo ""
echo -e "\033[33m### $* \033[0m"
"$@"
}
run ./inventario.sh -help
run ./inventario.sh -crear lista.csv 10
run ./inventario.sh -read lista.csv
run ./inventario.sh -add lista.csv servidor01 192.168.1.250 64 activo
run ./inventario.sh -find lista.csv servidor01
run ./inventario.sh -resumen lista.csv
run ./inventario.sh -del lista.csv servidor01
run ./inventario.sh -find lista.csv servidor01
run ./inventario.sh -del lista.csv servidor01
run ./inventario.sh -find lista.csv
run ./inventario.sh -read noexiste.csv
run ./inventario.sh
backup.sh#
Crea un script en Bash llamado backup.sh que gestione copias de seguridad comprimidas. Si ejecutas el script con ./backup.sh -help, debe mostrar la siguiente ayuda:
-help : muestra la ayuda
<directorio> : Crea backups/backup_<directorio>_<fecha>.tar.gz
-lista : Muestra los backups con su tamaño
-limpiar <días> : Borra los backups con más de <días> días, por defecto 7
-restaurar <archivo> : Extrae el backup en el directorio restaurado
Si ejecutas el script sin argumentos
./backup.sh, también debe mostrar la ayuda.Si ejecutas
./backup.sh <directorio>creará el directoriobackupssi no existe y dentro unbackup_<directorio>_<fecha>.tar.gz, si<directorio>no existe mostrará un error:./backup.sh ficheros Creado backups/backup_ficheros_2026-07-07_1030.tar.gz
Si ejecutas
./backup.sh -listamostrará los backups con su tamaño (consejo:du -h).Si ejecutas
./backup.sh -limpiar <días>borrará los backups con más de<días>días mostrando cuáles borra, por defecto 7 días (consejo:find -mtime +N, para probarlo envejece un backup contouch -d "10 days ago" <archivo>).Si ejecutas
./backup.sh -restaurar <archivo>lo extraerá dentro del directoriorestaurado(consejo:tar -xzf <archivo> -C restaurado).
Consejos:
date +%F_%H%Mda la fecha con el formato2026-07-07_1030.basename <ruta>se queda con el último componente de la ruta, para construir el nombre del backup.
#!/bin/bash
backup_dir="backups"
function show_help() {
echo -e "\033[32m-help : muestra la ayuda\033[0m"
echo -e "\033[32m<directorio> : Crea backups/backup_<directorio>_<fecha>.tar.gz\033[0m"
echo -e "\033[32m-lista : Muestra los backups con su tamaño\033[0m"
echo -e "\033[32m-limpiar <días> : Borra los backups con más de <días> días, por defecto 7\033[0m"
echo -e "\033[32m-restaurar <archivo> : Extrae el backup en el directorio restaurado\033[0m"
}
if [[ $1 == '-help' ]] || [[ $# -eq 0 ]]
then
show_help
fi
if [[ $1 == '-lista' ]]
then
if test -d $backup_dir
then
du -h $backup_dir/*.tar.gz
else
echo -e "\033[31m No hay backups\033[0m"
fi
fi
if [[ $1 == '-limpiar' ]]
then
dias=${2:-7}
antiguos=$(find $backup_dir -name "*.tar.gz" -mtime +$dias 2>/dev/null)
if test -z "$antiguos"
then
echo -e "\033[31m No hay backups con más de $dias días\033[0m"
else
echo "$antiguos"
find $backup_dir -name "*.tar.gz" -mtime +$dias -delete
echo -e "\033[32m Borrados \033[0m"
fi
fi
if [[ $1 == '-restaurar' ]]
then
if test -f "$2"
then
mkdir -p restaurado
tar -xzf $2 -C restaurado
echo -e "\033[32m Restaurado $2 en restaurado/ \033[0m"
else
echo -e "\033[31m El archivo $2 no existe\033[0m"
fi
fi
if [[ $# -ge 1 && $1 != -* ]] # si no empieza por - es el directorio a copiar
then
if test -d $1
then
mkdir -p $backup_dir
nombre=$backup_dir/backup_$(basename $1)_$(date +%F_%H%M).tar.gz
tar -czf $nombre $1
echo -e "\033[32m Creado $nombre \033[0m"
else
echo -e "\033[31m El directorio $1 no existe\033[0m"
fi
fi
backup_incremental.sh#
Mejora backup.sh creando backup_incremental.sh, que haga copias incrementales al estilo de rsnapshot: cada copia (snapshot) parece una copia completa, pero los ficheros que no han cambiado respecto al snapshot anterior no se copian de nuevo, sino que se enlazan con un hardlink, así que ocupan espacio en disco una sola vez.
Recibirá como argumentos el directorio origen (por defecto /home), el destino (por defecto /backups) y el número de snapshots a conservar (por defecto 7).
./backup_incremental.sh /home /backups 7
Primer backup (completo)
Creado /backups/snapshot_2026-07-07_210009
# tras modificar algún fichero y volver a ejecutarlo
Backup incremental respecto a snapshot_2026-07-07_210009
Creado /backups/snapshot_2026-07-07_210533
Para comprobar que los hardlinks funcionan, mira el número de inodo con ls -li: un fichero sin cambios tendrá el mismo inodo en los dos snapshots (es el mismo fichero físico), mientras que uno modificado tendrá inodos distintos.
Consejos:
rsync -a --delete --link-dest=<snapshot_anterior> <origen>/ <nuevo>/es la clave:--link-desthace los hardlinks de lo que no cambia.rsyncresuelve--link-destrespecto al directorio destino, así que pásale una ruta absoluta (realpath).Usa
date +%F_%H%M%Scon segundos en el nombre, si no dos backups en el mismo minuto colisionarían.Para la rotación,
ls -1d ... | head -n -Nlista todos menos los N últimos.
#!/bin/bash
# backup_incremental.sh - copias incrementales con hardlinks (estilo rsnapshot)
# Cada snapshot parece completo, pero los ficheros sin cambios son hardlinks
# al snapshot anterior, así que ocupan disco solo una vez.
origen=${1:-/home}
destino=${2:-/backups}
mantener=${3:-7} # número de snapshots a conservar
if [ ! -d "$origen" ]; then
echo -e "\033[31mEl directorio origen $origen no existe\033[0m"
exit 1
fi
mkdir -p "$destino"
destino=$(realpath "$destino") # rsync resuelve --link-dest respecto al destino, usamos ruta absoluta
nuevo="$destino/snapshot_$(date +%F_%H%M%S)"
ultimo=$(ls -1d $destino/snapshot_* 2>/dev/null | tail -1)
if [ -n "$ultimo" ]; then
# --link-dest: los ficheros iguales al último snapshot se crean como hardlinks
echo "Backup incremental respecto a $(basename $ultimo)"
rsync -a --delete --link-dest="$ultimo" "$origen/" "$nuevo/"
else
echo "Primer backup (completo)"
rsync -a --delete "$origen/" "$nuevo/"
fi
echo -e "\033[32mCreado $nuevo\033[0m"
# Rotación: borramos los snapshots más viejos, dejando los $mantener últimos
sobran=$(ls -1d $destino/snapshot_* 2>/dev/null | head -n -$mantener)
for viejo in $sobran
do
echo "Borrando snapshot antiguo $(basename $viejo)"
rm -rf "$viejo"
done
echo "Espacio real ocupado por todos los snapshots:"
du -sh "$destino"
dados.sh#
Sube al curso un script llamado dados.sh que obtenga dos números aleatorios entre el 1 y el 6, obtén la suma de los dos dados, Haz que salga por pantalla el numero de tiradas y el porcentaje de veces que sale cada una.
Haz que el número de tiradas lo reciba como un argumento, el caso de que no reciba ningún argumento haz que haga 1000 tiradas
$ ./dados.sh
De 1000 tiradas : 2(1%) 3(7%) 4(10%) 5(12%) 6(14%) 7(17%) 8(14%) 9(12%) 10(10%) 11(7%) 12(1%)
#!/bin/bash
tiradas=${1:-1000}
for ((i = 2; i <= 12; i++)); do
frecuencias[$i]=0
done
for ((i = 1; i <= tiradas; i++)); do
dado1=$((RANDOM % 6 + 1))
dado2=$((RANDOM % 6 + 1))
suma=$((dado1 + dado2))
frecuencias[$suma]=$((frecuencias[$suma]+1))
done
echo "De $tiradas tiradas:"
output=""
for ((i = 2; i <= 12; i++)); do
porcentaje=$((frecuencias[$i] * 100 / tiradas))
output+="$i(${porcentaje}%) "
done
echo "$output"
#!/bin/bash
function mostrar_ayuda() {
echo -e "\033[32m -help\033[0m"
echo -e "\033[32m -tiradas <nº tiradas> \033[0m"
echo -e "\033[32m -ndados <nº dados> \033[0m"
}
function tirar_ndados_ntiradas(){
for ((i = $ndados; i <= $((ndados*6)); i++)); do
frecuencias[$i]=0
done
for ((i = 1; i <= tiradas; i++)); do
suma=0
for (( j = 1; j <= ndados; j++)); do
dado[$j]=$((RANDOM % 6 + 1))
suma=$((suma + ${dado[$j]}))
done
frecuencias[$suma]=$((frecuencias[$suma]+1))
done
echo "De $tiradas tiradas para $ndados dados:"
for ((i = $ndados; i <= $((ndados))*6; i++)); do
porcentaje=$(echo "scale=2; ${frecuencias[$i]} * 100 / $tiradas" | bc -l)
echo "$i (${porcentaje}%)"
done
}
if [[ $# -eq 0 ]]
then
# Sin argumentos: mostrar ayuda
mostrar_ayuda
elif [[ $1 == "-help" ]]
then
mostrar_ayuda
else
tiradas=1000
ndados=2
for j in $@
do
shift
if [ $j == "-tiradas" ]
then
tiradas=$1
fi
if [ $j == "-ndados" ]
then
ndados=$1
fi
done
tirar_ndados_ntiradas
fi
adivina_cpu.sh#
Crea un script en Bash llamado adivina_cpu.sh que simule un juego automático de adivinanza en el que la CPU intenta adivinar un número secreto aleatorio, generado al inicio del programa. El número estará comprendido entre 1 y un valor máximo definido por la variable n_max_adivinar. En cada intento, la CPU elige otro número al azar dentro del rango posible, ajustando los límites mínimo y máximo según si el número es menor o mayor al número secreto.
El script debe cumplir con los siguientes requisitos:
No se deben repetir los números ya probados.
Tras cada intento, si el número elegido es menor que el número secreto, se actualiza el mínimo.
Si el número elegido es mayor, se actualiza el máximo.
El proceso se repite hasta que se adivine el número secreto.
Al final, se muestra el número total de intentos que necesitó la CPU para adivinar el número.
Cuando el usuario acierte haz que muestre el número de intentos.
#!/bin/bash
n_max_adivinar=20
numero_secreto=$((RANDOM % $n_max_adivinar + 1))
intento=0
comparar=-1
maximo=$n_max_adivinar
minimo=0
while [[ $comparar != 0 ]]
do
intento=$((intento+1))
numero_elegido=$((RANDOM % $((maximo-minimo)) + 1 + $minimo))
repetido=1
while [[ $repetido -eq 1 ]]
do
repetido=0
for((i=0;i<=${#I[@]};i++))
do
if [[ ${I[$i]} -eq $numero_elegido ]]
then
repetido=1
fi
done
if [[ $repetido -eq 1 ]]
then
numero_elegido=$((RANDOM % $((maximo-minimo)) + 1 + $minimo))
fi
done
if [[ $numero_elegido -lt $numero_secreto ]]
then
comparar=-1
minimo=$numero_elegido
fi
if [[ $numero_elegido -gt $numero_secreto ]]
then
comparar=1
maximo=$numero_elegido
fi
if [[ $numero_elegido -eq $numero_secreto ]]
then
comparar=0
fi
#echo $intento $numero_secreto $numero_elegido $comparar $maximo $minimo $repetido
I[$intento]=$numero_elegido
done
#sacamos el número de intentos que ha hecho hasta adividnar el resultado
echo $intento
Para testearlo puedes usar:
ntot=100
sum=0
for((i=0;i<$ntot;i++))
do
n=$(./adivina_cpu.sh)
sum=$((sum+n))
done
resultado=$(echo "1/($sum/$ntot)" | bc -l)
printf "%.2f\n" "$resultado"
0.23
Como se puede ver, la probabilidad de acertar el número se incrementa notablemente gracias a dos factores clave del algoritmo: evitar repetir números y ajustar dinámicamente los valores máximo y mínimo tras cada intento.
Si no se evitaran los números repetidos y no se acotara el intervalo con el mínimo y el máximo, cada intento sería completamente aleatorio dentro del rango total (por ejemplo, del 1 al 20). En ese caso, la probabilidad de acertar en un intento sería simplemente: 1/20=0.05 es decir, solo un 5% de probabilidad frente al 23%
tragaperras.sh#
Crea un script llamado tragaperras.sh que simule una máquina tragaperras con tres rodillos. Cada rodillo muestra un número aleatorio del 0 al 9. Las reglas del juego son las siguientes:
Cada partida cuesta 1 moneda.
Si aparecen dos números iguales, el jugador gana 2 monedas.
Si aparecen tres números iguales, el jugador gana 3 monedas.
Si los tres números son 7, el jugador gana 10 monedas.
El programa debe simular una cantidad significativa de partidas y calcular:
El número total de monedas ganadas.
El número total de monedas gastadas.
El balance final.
Y, finalmente, responder a la pregunta: ¿Es rentable esta tragaperras para el jugador?
Haz que el número de tiradas lo reciba como un argumento, el caso de que no reciba ningún argumento haz que haga 1000 tiradas
#!/bin/bash
tiradas=${1:-10000}
ganadas=0
gastadas=0
for ((i=1; i<=tiradas; i++)); do
gastadas=$((gastadas+1))
#generamos cada rodillo
r1=$((RANDOM % 10))
r2=$((RANDOM % 10))
r3=$((RANDOM % 10))
if [[ $r1 -eq $r2 && $r2 -eq $r3 ]]; then
if [[ $r1 -eq 7 ]]; then #caso de 777
ganadas=$((ganadas+10))
else #caso 3 iguales sin contar el 777
ganadas=$((ganadas+3))
fi
elif [[ $r1 -eq $r2 || $r1 -eq $r3 || $r2 -eq $r3 ]]; then #caso 2 iguales sin contar 3 iguales
ganadas=$((ganadas+2))
fi
done
echo "Tiradas realizadas: $tiradas"
echo "Monedas gastadas: $gastadas"
echo "Monedas ganadas: $ganadas"
balance=$((ganadas - gastadas))
echo "Balance final: $balance"
if ((balance > 0)); then
echo "Esta tragaperras ES rentable para el jugador."
else
echo "Esta tragaperras NO es rentable para el jugador."
fi
flor.sh#
Crea un script llamado flor.sh que juegue a adivinar una palabra letra a letra: con cada fallo la flor pierde un pétalo y al sexto fallo la flor se marchita y se pierde la partida. El script debe utilizar las siguientes palabras como ejemplo:
palabra=("PYTHON" "LINUX" "BASH" "GITHUB" "DOCKER")
# La flor completa:
@ @ @
@ (o) @
|
\|/
=========
# La flor marchita:
(o)
\
\|/
=========
#!/bin/bash
palabra=("PYTHON" "LINUX" "BASH" "GITHUB" "DOCKER")
indice=$((RANDOM % ${#palabra[@]}))
secreta="${palabra[$indice]}"
longitud=${#secreta}
oculta=$(echo "$secreta" | sed 's/./_/g')
intentos=0
fallos=0
max_fallos=6
letras_intentadas=()
dibujar() {
clear
case $fallos in
0)
echo " @ @ @"
echo " @ (o) @"
echo " |"
echo " \\|/"
echo "========="
;;
1)
echo " @ @ @"
echo " (o) @"
echo " |"
echo " \\|/"
echo "========="
;;
2)
echo " @ @ @"
echo " (o)"
echo " |"
echo " \\|/"
echo "========="
;;
3)
echo " @ @"
echo " (o)"
echo " |"
echo " \\|/"
echo "========="
;;
4)
echo " @"
echo " (o)"
echo " |"
echo " \\|/"
echo "========="
;;
5)
echo ""
echo " (o)"
echo " |"
echo " \\|/"
echo "========="
;;
6)
echo ""
echo " (o)"
echo " \\"
echo " \\|/"
echo "========="
;;
esac
}
echo "¡Bienvenido al juego de la flor!"
echo "Adivina la palabra antes de que la flor pierda todos sus pétalos"
dibujar
while [[ "$oculta" != "$secreta" && $fallos -lt $max_fallos ]]; do
echo "Palabra: $oculta"
echo "Letras intentadas: ${letras_intentadas[@]}"
read -p "Introduce una letra: " letra
letra=$(echo "$letra" | tr '[:lower:]' '[:upper:]')
if [[ " ${letras_intentadas[@]} " =~ " $letra " ]]; then
echo "Ya intentaste esa letra. Prueba otra."
continue
fi
letras_intentadas+=("$letra")
if [[ "$secreta" =~ "$letra" ]]; then
# Reemplazar guiones bajos por la letra adivinada
for ((i = 0; i < $longitud; i++)); do
if [[ "${secreta:$i:1}" == "$letra" ]]; then
oculta=$(echo "$oculta" | sed "s/./$letra/$((i + 1))")
fi
done
echo "¡Bien hecho! La letra '$letra' está en la palabra."
else
((fallos++))
echo "La letra '$letra' no está en la palabra. La flor pierde un pétalo..."
fi
dibujar
done
if [[ "$oculta" == "$secreta" ]]; then
echo "¡Felicidades! Adivinaste la palabra: $secreta"
else
echo "¡Oh no! La flor se ha marchitado."
echo "La palabra era: $secreta"
fi
Administración y seguridad#
auditoria.sh#
Crea un script llamado auditoria.sh que haga un chequeo de seguridad básico del sistema, imprimiendo por cada comprobación si está bien ([ OK ] en verde) o mal ([FALLO] en rojo), y al final cuántos problemas ha encontrado. Ejecútalo como root para poder leer /etc/shadow.
Comprobaciones:
Que solo root tenga UID 0 (campo 3 de
/etc/passwd).Que no haya cuentas sin contraseña (campo 2 de
/etc/shadowvacío).Que
/etc/shadowtenga permisos640o más restrictivos.Quién puede usar
sudo(miembros del grupo sudo).Qué puertos están a la escucha (
ss -tlnp).
sudo ./auditoria.sh
=== Auditoría de seguridad de servidor1 ===
--- Usuarios con UID 0 ---
[ OK ] Solo root tiene UID 0
...
=== 0 problemas encontrados ===
Consejo: haz que el script termine con exit $problemas, así el número de fallos queda como código de salida y se puede usar desde otro script o herramienta de monitorización.
#!/bin/bash
# auditoria.sh - chequeo de seguridad básico del sistema
# Ejecutar como root para poder leer /etc/shadow
problemas=0
ok() { echo -e "\033[32m[ OK ]\033[0m $1"; }
fallo() { echo -e "\033[31m[FALLO]\033[0m $1"; problemas=$((problemas+1)); }
echo "=== Auditoría de seguridad de $(hostname) ==="
# 1. Usuarios con UID 0 (solo debería estar root)
echo "--- Usuarios con UID 0 ---"
uid0=$(awk -F: '$3 == 0 {print $1}' /etc/passwd)
if [ "$uid0" == "root" ]; then
ok "Solo root tiene UID 0"
else
fallo "Hay más usuarios con UID 0: $uid0"
fi
# 2. Cuentas sin contraseña
echo "--- Cuentas sin contraseña ---"
sin_pass=$(awk -F: '($2 == "") {print $1}' /etc/shadow 2>/dev/null)
if [ -z "$sin_pass" ]; then
ok "No hay cuentas sin contraseña"
else
fallo "Cuentas sin contraseña: $sin_pass"
fi
# 3. Permisos de /etc/shadow (debe ser 640 o más restrictivo)
echo "--- Permisos de /etc/shadow ---"
perm=$(stat -c '%a' /etc/shadow 2>/dev/null)
if [ "$perm" == "640" ] || [ "$perm" == "600" ]; then
ok "/etc/shadow tiene permisos $perm"
else
fallo "/etc/shadow tiene permisos $perm (debería ser 640)"
fi
# 4. Quién puede usar sudo
echo "--- Miembros del grupo sudo ---"
sudoers=$(getent group sudo | cut -d: -f4)
echo "Pueden usar sudo: ${sudoers:-nadie}"
# 5. Puertos a la escucha
echo "--- Puertos a la escucha ---"
ss -tlnp 2>/dev/null | tail -n +2 | tr -s ' ' | cut -d' ' -f4 | sort -u
echo "=== $problemas problemas encontrados ==="
exit $problemas
cuentas_inactivas.sh#
Crea un script llamado cuentas_inactivas.sh que detecte los usuarios reales (UID >= 1000) que no acceden al sistema desde hace más de N días (por defecto 90), y que con la opción -bloquear además los bloquee. Ejecútalo como root.
sudo ./cuentas_inactivas.sh 90
=== Usuarios sin acceso en los últimos 90 días ===
antiguo1 (inactivo, usa -bloquear para bloquearlo)
sudo ./cuentas_inactivas.sh 90 -bloquear
antiguo1 bloqueado
Es la versión "de administrador" de lastlog.sh: lastlog -b N lista quién no entra desde hace más de N días, y usermod -L bloquea una cuenta. Ten cuidado de no bloquear cuentas del sistema (por eso filtramos por UID >= 1000).
#!/bin/bash
# cuentas_inactivas.sh - detecta (y opcionalmente bloquea) cuentas sin uso
# Ejecutar como root
dias=${1:-90} # días de inactividad, por defecto 90
bloquear=$2 # si es "-bloquear" además de listar, bloquea las cuentas
echo -e "\033[34m=== Usuarios sin acceso en los últimos $dias días ===\033[0m"
# lastlog -b N lista los usuarios que no entran desde hace más de N días
# quitamos la cabecera y los que nunca han entrado (**Never logged in**)
lastlog -b $dias 2>/dev/null | tail -n +2 | grep -v "Never logged in" | tr -s ' ' | cut -d' ' -f1 |
while read usuario
do
# solo cuentas de usuario real (UID >= 1000), no las del sistema
uid=$(id -u "$usuario" 2>/dev/null)
if [ -n "$uid" ] && [ "$uid" -ge 1000 ]; then
if [ "$bloquear" == "-bloquear" ]; then
usermod -L "$usuario"
echo -e "\033[31m$usuario bloqueado\033[0m"
else
echo "$usuario (inactivo, usa -bloquear para bloquearlo)"
fi
fi
done
Gestión de usuarios locales#
usuarios_WSL.sh#
Crea un script llamado usuarios_WSL.sh, que cumpla las siguientes condiciones:
./usuarios_WSL.sh -help
-help Mostrar esta ayuda.
-crear <N> Crear N usuarios de forma aleatoria dentro de los grupos X, Y o Z.
-borrar Borrar todos los usuarios creados por este script.
-listar Mostrar los usuarios por grupo creados por este script.
Opción -crear <N>: Creará N usuarios con nombres generados automáticamente con el siguiente formato: uX01, uY23, uZ15, etc.,
La letra (X, Y o Z) corresponde a un grupo al que se asignará el usuario.
El número es un sufijo aleatorio de dos cifras (01 a 99).
Si no tenemos <N> creará por defecto 10 usuarios
#!/bin/bash
function show_help() {
echo '
-help Mostrar esta ayuda.
-crear <N> Crear N usuarios de forma aleatoria dentro de los grupos X, Y o Z.
-borrar Borrar todos los usuarios creados por este script.
-listar Mostrar los usuarios por grupo creados por este script.
'
}
grupos=(X Y Z)
if [[ $# -gt 0 ]]
then
if [[ $1 == "-help" ]]
then
show_help
fi
if [[ $1 == "-crear" ]]
then
num_usuarios=${2:-10}
for ((i=1; i<=num_usuarios; i++)); do
grupo=${grupos[$RANDOM % ${#grupos[@]}]}
sufijo=$(printf "%02d" $((RANDOM % 99 )))
usuario="u${grupo}${sufijo}"
useradd -g $grupo -d /home/$usuario -m -s /bin/bash -p $( mkpasswd -m sha-512 -s cambiame) $usuario
echo "Usuario $usuario creado en el grupo $grupo con contraseña por defecto 'cambiame'."
done
fi
if [[ $1 == "-borrar" ]]
then
for g in ${grupos[@]};
do
echo Borro usuarios del grupo $g
for u in $(cat /etc/passwd | cut -d':' -f1 | grep u$g);
do
echo Borramos el usuario $u
userdel -r $u
done
done
fi
if [[ $1 == "-listar" ]]
then
for g in ${grupos[@]};
do
echo Usuarios del grupo $g
for u in $(cat /etc/passwd | cut -d':' -f1 | grep u$g);
do
echo $u
done
done
fi
else
show_help
fi
usuarios.sh#
Crea un script llamado usuarios.sh, utiliza para ello un clon enlazado de la "MV Ubuntu Server 24.04"
./usuarios.sh -help
usuarios.sh -addgroup <grupo> : Crea un grupo si no existe
usuarios.sh -delgroup <grupo> : Elimina un grupo si existe
usuarios.sh -adduser <usuario> [grupo]: Crea un usuario en el grupo especificado
: Si el grupo no existe lo crea primero
: Si no damos grupo usa por defecto el grupo usuario1
usuarios.sh -deluser <usuario> : Elimina un usuario si existe
usuarios.sh -lista : Lista todos los grupos y sus usuarios
En el caso de ejecutar ./usuarios.sh sin argumentos obtendremos el mensaje de ayuda.
Chequea tu script con las siguientes características:
cat usuarios.sh
for g in GA GB GC GD
do
./usuarios.sh -addgroup $g
for u in 01 02 03 04
do
usuario=usuario_${g}_${u}
./usuarios.sh -adduser ${usuario} ${g}
done
done
./usuarios.sh -lista
./usuarios.sh -help
El script muestra una ayuda con las opciones que puede tiene
#!/bin/bash
function show_help() {
echo "Uso del script:"
echo "./usuarios.sh -addgroup <grupo> : Crea un grupo si no existe"
echo "./usuarios.sh -delgroup <grupo> : Elimina un grupo si existe"
echo "./usuarios.sh -adduser <usuario> [grupo]: Crea un usuario en el grupo especificado (o en uno con su mismo nombre)"
echo "./usuarios.sh -deluser <usuario> : Elimina un usuario si existe"
echo "./usuarios.sh -lista : Lista todos los grupos y sus usuarios"
}
if [[ $# -gt 0 ]]
then
if [[ $1 == "-addgroup" ]]
then
if [[ $(grep -c $2 /etc/group) -gt 0 ]]
then
echo "No se crea el grupo, el grupo $2 existe."
else
echo "Creamos el grupo $2"
groupadd $2
fi
fi
if [[ $1 == "-delgroup" ]]
then
groupdel $2
fi
if [[ $1 == "-adduser" ]]
then
usuario=$2
grupo=${3:-$usuario}
echo "creamos el $usuario en $grupo"
if [[ $(grep -c $usuario /etc/passwd) -gt 0 ]]
then
echo "No se crea el usuario, el usuario $usuario ya existe."
else
if [[ $(grep -c $grupo /etc/group) -eq 0 ]]
then
groupadd $grupo
echo "Creamos el grupo $grupo"
fi
useradd -g $grupo -d /home/$usuario -m -s /bin/bash -p $( mkpasswd -m sha-512 -s cambiame) $usuario
echo "Usuario $usuario creado en el grupo $grupo con contraseña por defecto 'cambiame'."
fi
fi
if [[ $1 == "-deluser" ]]
then
if [[ $(grep -c $2 /etc/passwd) -gt 0 ]]
then
userdel -r $2
echo "Usuario $2 eliminado."
else
echo "No se borra el usuario, el usuario $2 no existe."
fi
fi
if [[ "$1" == "-lista" ]]
then
#solo listamos los grupos que tienen usuarios
for g in $(cut -d':' -f1 /etc/group)
do
if [[ $(members $g ) != "" ]]
then
echo ----- $g------
members $g
fi
done
fi
else
show_help
fi
rsync_usuarios.sh#
Crea tres máquinas virtuales con Ubuntu Server:
Servidor principal llamado compute-0-0
Clientes compute-0-1 y compute-0-2.
Permite la conexión desde compute-0-0 al usuario root de compute-0-1 y compute-0-2 sin utilizar contraseña, mediante la exportación de claves SSH públicas.
Escribe un script para clonar usuarios, el script deberá copiar los usuarios del sistema desde compute-0-0 a compute-0-1 y compute-0-2 utilizando el comando rsync para transferir los siguientes archivos:
/etc/passwd
/etc/shadow
/etc/group
El script debe comprobar que los directorios /home/usuario existen en los clientes. Si no existen, deberá crearlos y configurar el acceso SSH de los usuarios.
En los clientes, el script creará el directorio /home/usuario/.ssh para cada usuario (si no existe) y copiará su clave pública desde el servidor compute-0-0, de modo que los usuarios puedan iniciar sesión por SSH sin contraseña."
clientes='compute-0-1 compute-0-2'
for cpu in $clientes
do
rsync -av --delete /etc/passwd $cpu:/etc/passwd
rsync -av --delete /etc/shadow $cpu:/etc/shadow
rsync -av --delete /etc/group $cpu:/etc/group
done
u=usuario_GD_04
g=GD
for u in $(cat /etc/passwd | grep usuari | cut -d':' -f1)
do
g=$(groups $u | cut -d':' -f2 | cut -d' ' -f2)
if test -d /home/$u
then
echo no creamos la carpeta /home/$u ya que existe
else
cp -r home_usuario_server /home/$u
sed -i "s/usuario_X/$u/" /home/$u/.ssh/id_ed25519.pub
chown -R $u:$g /home/$u
for cpu in $clientes
do
cp -r home_usuario_cliente $u
sed -i "s/usuario_X/$u/" $u/.ssh/authorized_keys
scp -r $u $cpu:/home/
ssh $cpu chown -R $u:$g /home/$u
rm -fr $u
done
fi
done
#rm -fr /home/usuario* ; ssh compute-0-1 rm -fr /home/usu* ; ssh compute-0-2 rm
Necesitamos los siguientes archivos auxiliares
root@compute-0-0:~# ls -la home_usuario_cliente/
total 32
drwxr-xr-x 4 root root 4096 may 28 08:05 .
drwx------ 6 root root 4096 jun 3 09:55 ..
-rw------- 1 root root 68 may 28 08:05 .bash_history
-rw-r--r-- 1 root root 220 may 28 08:05 .bash_logout
-rw-r--r-- 1 root root 3771 may 28 08:05 .bashrc
drwx------ 2 root root 4096 may 28 08:05 .cache
-rw-r--r-- 1 root root 807 may 28 08:05 .profile
drwxr-xr-x 2 root root 4096 may 28 08:15 .ssh
root@compute-0-0:~# ls -la home_usuario_server/
total 28
drwxr-x--- 3 root root 4096 may 28 08:04 .
drwx------ 6 root root 4096 jun 3 09:55 ..
-rw------- 1 root root 163 may 28 08:04 .bash_history
-rw-r--r-- 1 root root 220 may 28 08:04 .bash_logout
-rw-r--r-- 1 root root 3771 may 28 08:04 .bashrc
-rw-r--r-- 1 root root 807 may 28 08:04 .profile
drwx------ 2 root root 4096 may 28 08:11 .ssh
crear_usuarios_lista.sh#
Genera la siguiente lista de usuarios en el archivo lista.dat
for((i=0;i<40;i++))
do
R=$RANDOM
echo tunombre_$R G$(($R%4))
done > lista.dat
Crea un script llamado crear_usuarios_lista.sh que genere por defecto los usuarios que encuentra en el archivo lista.dat, con la contraseña
cambiame, haz que si recibe el nombre de otro archivo como lista lo utilice. En el caso de que el grupo no exista haz que lo cree en el sistemaCrea otro script llamado borrar_usuarios_lista.sh que borre los usuarios que aparecen en el archivo lista.dat, haz que utilice este archivo por defecto en el caso de no recibir ningun archivo.
Crea otro script llamado crear_usuarios_grupo_lista.sh que lea solo la primera columna de un archivo llamado nombre_grupo.dat, creará todos los usuarios dentro del grupo llamado nombre_grupo, en el caso de que no exista creara primero el grupo.
Crea otro script llamdo borrar_usuarios_grupo_lista.sh que lea solo la primera columna de un archivo llamado nombre_grupo.dat, borrará todos los usuarios que encuentre en la lista, al final y sólo en el caso de que el grupo se haya quedado vacío se borrará tambien el grupo.
#!/bin/bash
#Vamos a crear los usuarios que aparecen en la lista.dat
#$cat listda.dat
# usuario1 Grupo1
# usuario2 Grupo2
# usuario3 Grupo1
archivo=${1:-lista.dat}
for usuario in $(cat $archivo | cut -d' ' -f1 )
do
grupo=$(grep $usuario $archivo | cut -d' ' -f2)
if [[ $(grep -c $usuario /etc/passwd) -gt 0 ]]
then
echo -e "\033[31m No se crea el usuario, el usuario $usuario ya existe. \033[0m"
else
if [[ $(grep -c $grupo /etc/group) -eq 0 ]]
then
groupadd $grupo
echo -e "\033[34m Creamos el grupo $grupo \033[0m"
fi
useradd -g $grupo -d /home/$usuario -m -s /bin/bash -p $( mkpasswd -m sha-512 -s cambiame) $usuario
echo -e "\033[34m Creamos el usuario $usuario en el grupo $grupo con contraseña por defecto 'cambiame'.\033[0m"
fi
done
#!/bin/bash
#Vamos a crear los usuarios que aparecen en la lista.dat
archivo=${1:-lista.dat}
for usuario in $(cat $archivo | cut -d' ' -f1 )
do
if [[ $(grep -c $usuario /etc/passwd) -gt 0 ]]
then
echo -e "\033[34m Borramos el $usuario \033[0m"
userdel -r $usuario
else
echo -e "\033[31m El usuario $usuario no existe \033[0m"
fi
done
#!/bin/bash
#Vamos a crear los usuarios que aparecen en el archvio grupo.dat
if [[ $# == 0 ]]
then
echo -e "\033[31m El primer argumento es el archivo con el nombre del grupo.dat \033[0m"
else
if test -e $1
then
archivo=$1
echo -e "\033[33m Leemos el archivo $archivo \033[0m"
grupo=$(echo $archivo | sed 's/.dat//')
for usuario in $(cat $archivo | cut -d' ' -f1 )
do
if [[ $(grep -c $usuario /etc/passwd) -gt 0 ]]
then
echo -e "\033[31m No se crea el usuario, el usuario $usuario ya existe.\033[0m"
else
if [[ $(grep -c $grupo /etc/group) -eq 0 ]]
then
groupadd $grupo
echo -e "\033[34m Creamos el grupo $grupo \033[0m"
fi
echo -e "\033[34m Creamos el usuario $usuario en el grupo $grupo \033[0m"
useradd -g $grupo -d /home/$usuario -m -s /bin/bash -p $( mkpasswd -m sha-512 -s cambiame) $usuario
echo -e "\033[34m Usuario $usuario creado en el grupo $grupo con contraseña por defecto 'cambiame'.\033[0m"
fi
done
else
echo -e "\033[31m El archivo $1 no existe \033[0m"
fi
fi
#!/bin/bash
if [[ $# == 0 ]]
then
echo -e "\033[31m El primer argumento es el archivo con el nombre del grupo.dat \033[0m"
else
if test -e $1
then
archivo=$1
echo -e "\033[33m Leemos el archivo $archivo \033[0m"
grupo=$(echo $archivo | sed 's/.dat//')
idg=$(grep $grupo /etc/group | cut -d':' -f3)
for usuario in $(cat $archivo | cut -d' ' -f1 )
do
if [[ $(grep -c $usuario /etc/passwd) -gt 0 ]]
then
userdel -r $usuario
echo -e "\033[34m Borramos el usuario $usuario $grupo \033[0m"
else
echo -e "\033[31m No se borra el usuario, el usuario $usuario no existe.\033[0m"
fi
done
n_usuarios_grupo=$(cat /etc/passwd | cut -d':' -f4 | sort | uniq -c | grep $idg | tr -s ' ' | cut -d' ' -f2)
if [[ $n_usuarios_grupo -eq 0 ]]
then
echo -e "\033[34m Borramos el $grupo ya que no tiene usuarios \033[0m"
groupdel $grupo
else
echo -e "\033[31m No se borra el $grupo ya que tiene $n_usuarios_grupo usuarios \033[0m"
fi
else
echo -e "\033[31m El archivo $1 no existe \033[0m"
fi
fi
Gestión de usuarios LDAP#
usuarios_ldap.sh#
Crea un script llamado usuarios_ldap.sh, utiliza para ello un clon enlazado de la 'MV Ubuntu Server 24.04' con un ldap configurado aqui
Uso del script:
./usuarios_ldap.sh -addgroup <grupo> : Crea un grupo si no existe
./usuarios_ldap.sh -delgroup <grupo> : Elimina un grupo si existe
./usuarios_ldap.sh -lsgroup : Elimina un grupo si existe
./usuarios_ldap.sh -adduser <usuario> [grupo]: Crea un usuario en el grupo especificado
./usuarios_ldap.sh -deluser <usuario> : Elimina un usuario si existe
./usuarios_ldap.sh -lista : Lista todos los grupos y sus usuarios
./usuarios_ldap.sh -lsuser : Elimina un grupo si existe
#!/bin/bash
LDAP="dc=ldap,dc=tunombre,dc=local"
LDAPadmin="cn=admin,$LDAP"
password=alumno
passwd_defecto_usuario=cambiame
function crear_grupo(){
NAMEG=$1 #GA
NUMBERGID=$2 #501
cat << EOF > grupo.ldif
dn: cn=${NAMEG},ou=grupos,$LDAP
objectClass: posixGroup
cn: ${NAMEG}
gidNumber: ${NUMBERGID}
EOF
ldapadd -x -D $LDAPadmin -w $password -f grupo.ldif
rm -fr grupo.ldif
}
function crear_usuario(){
NAME=$1 #tunombre1
NUMBERID=$2 #1001
NUMBERGID=$( ldapsearch -xLLL -D $LDAPadmin -w $password -b $LDAP cn=$3 gidNumber | grep gid | cut -d':' -f2)
cat << EOF > usuarios.ldif
dn: uid=${NAME},ou=usuarios,$LDAP
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: ${NAME}
cn: ${NAME}
sn: ${NAME}
gidNumber: ${NUMBERGID}
uidNumber: ${NUMBERID}
userPassword: $passwd_defecto_usuario
homeDirectory: /home/$NAME
loginShell: /bin/bash
EOF
ldapadd -x -D $LDAPadmin -w $password -f usuarios.ldif
#rm -fr usuarios.ldif
}
function show_help() {
echo -e "\033[34m Uso del script:\033[0m"
echo -e "\033[34m ./usuarios_ldap.sh -addgroup <grupo> : Crea un grupo si no existe\033[0m"
echo -e "\033[34m ./usuarios_ldap.sh -delgroup <grupo> : Elimina un grupo si existe\033[0m"
echo -e "\033[34m ./usuarios_ldap.sh -lsgroup : Elimina un grupo si existe\033[0m"
echo -e "\033[34m ./usuarios_ldap.sh -adduser <usuario> [grupo]: Crea un usuario en el grupo especificado \033[0m"
echo -e "\033[34m ./usuarios_ldap.sh -deluser <usuario> : Elimina un usuario si existe\033[0m"
echo -e "\033[34m ./usuarios_ldap.sh -lista : Lista todos los grupos y sus usuarios\033[0m"
echo -e "\033[34m ./usuarios_ldap.sh -lsuser : Elimina un grupo si existe\033[0m"
}
if [[ $# -gt 0 ]]
then
if [[ $1 == "-addgroup" ]]
then
if [[ $(ldapsearch -xLLL -b $LDAP cn=$2 | grep -c 'ldap') -gt 0 ]]
then
echo -e "\033[31m No se crea el grupo, el grupo $2 existe. \033[0m"
else
echo -e "\033[34m Creamos el grupo $2 \033[0m"
#tomamos el ultimo gidNumbrer:
gidN=$(ldapsearch -xLLL -b $LDAP | grep gidNumber | cut -d':' -f2 | tail -1)
if [ -z $gidN ] #-z indica que la variable esta vacía
then
gidN=500
fi
gidN=$((gidN+1))
crear_grupo $2 $gidN
fi
fi
if [[ $1 == "-delgroup" ]]
then
if [[ $(ldapsearch -xLLL -b $LDAP cn=$2 | grep -c 'ldap') -gt 0 ]]
then
ldapdelete -x -w $password -D $LDAPadmin "cn=$2,ou=grupos,$LDAP"
echo -e "\033[34m Borramos el grupo $2 \033[0m"
else
echo -e "\033[31m No se borra el grupo, el grupo $2 no existe. \033[0m"
fi
fi
if [[ $1 == "-lsgroup" ]]
then
ldapsearch -xLLL -D $LDAPadmin -w $password -b $LDAP "(objectClass=posixGroup)" cn gidNumber
fi
if [[ $1 == "-adduser" ]]
then
if [[ $(ldapsearch -xLLL -b $LDAP cn=$2 | grep -c 'ldap') -gt 0 ]]
then
echo -e "\033[31m No se crea el usuario, $2 existe. \033[0m"
else
#tomamos el ultimo gidNumbrer:
uidN=$(ldapsearch -xLLL -b $LDAP | grep uidNumber | cut -d':' -f2 | tail -1)
if [ -z $uidN ] #-z indica que la variable esta vacía
then
uidN=1000
fi
uidN=$((uidN+1))
grupo=$3
if [ -z $grupo ]
then
echo -e "\033[31m No se crea el usuario, necesitamos un grupo. \033[0m"
else
echo -e "\033[34m Creamos el usuario $2 \033[0m"
crear_usuario $2 $uidN $grupo
fi
fi
fi
if [[ $1 == "-deluser" ]]
then
if [[ $(ldapsearch -xLLL -b $LDAP uid=$2 | grep -c 'ldap') -gt 0 ]]
then
ldapdelete -x -w $password -D $LDAPadmin "uid=$2,ou=usuarios,$LDAP"
echo -e "\033[34m Borramos el usuario $2 \033[0m"
else
echo -e "\033[31m No se borra el usuario, el usuario $2 no existe. \033[0m"
fi
fi
if [[ $1 == "-lsuser" ]]
then
ldapsearch -xLLL -D $LDAPadmin -w $password -b $LDAP "(objectClass=posixAccount)" cn uidNumber
fi
else
show_help
fi
$ head -4 lista.dat
tunombre_73 GA
tunombre_36 GC
tunombre_82 GC
tunombre_07 GC
for((i=0;i<$(wc -l lista.dat | cut -d' ' -f1);i++))
do
./usuarios_ldap.sh -adduser $(head -$i lista.dat | tail -1)
done
usuarios_lista_ldap.sh#
Crea un script llamado usuarios_lista_ldap.sh, haz que todos los usuarios se lean de un archivo llamado grupo.dat. Haz que todos los usuarios pertenezcan al grupo con el mismo nombre que el archivo sin la extensión .dat. En el caso de que no exista el grupo haz que se cree.
En el archivo grupo.dat, hay una lista de emails, haz que se cree el usuario correspondiente al email, es decir usuario1@gmail.com creara el usuario usuario1. En el caso de -borrar borrara todos los usuarios del archivo, finalmente si no quedan usuarios en el grupo borra el grupo
./usuarios_lista_ldap.sh -help
./usuarios_lista_ldap.sh -crear <archivo.dat>
./usuarios_lista_ldap.sh -borrar <archivo.dat>
#head -2 grupo.dat
usuario1@gmail.com
usuario2@gmail.com
#!/bin/bash
LDAP="dc=ldap,dc=tunombre,dc=local"
LDAPadmin="cn=admin,$LDAP"
password=alumno
passwd_defecto_usuario=cambiame
function crear_grupo(){
NAMEG=$1 #GA
NUMBERGID=$2 #501
cat << EOF > grupo.ldif
dn: cn=${NAMEG},ou=grupos,$LDAP
objectClass: posixGroup
cn: ${NAMEG}
gidNumber: ${NUMBERGID}
EOF
ldapadd -x -D $LDAPadmin -w $password -f grupo.ldif
rm -fr grupo.ldif
}
function crear_usuario(){
NAME=$1 #tunombre1
NUMBERID=$2 #1001
NUMBERGID=$(ldapsearch -xLLL -D $LDAPadmin -w $password -b $LDAP cn=$3 gidNumber | grep gid | cut -d':' -f2)
echo ldapsearch -xLLL -D $LDAPadmin -w $password -b $LDAP cn=$3 gidNumber | grep gid | cut -d':' -f2
echo NUMBERGID=$NUMBERGID
cat << EOF > usuarios.ldif
dn: uid=${NAME},ou=usuarios,$LDAP
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: ${NAME}
cn: ${NAME}
sn: ${NAME}
gidNumber: ${NUMBERGID}
uidNumber: ${NUMBERID}
userPassword: $passwd_defecto_usuario
homeDirectory: /home/$NAME
loginShell: /bin/bash
EOF
ldapadd -x -D $LDAPadmin -w $password -f usuarios.ldif
rm -fr usuarios.ldif
}
function show_help() {
echo -e "\033[34m
./usuarios_lista_ldap.sh -help
./usuarios_lista_ldap.sh -crear <archivo.dat>
./usuarios_lista_ldap.sh -borrar <archivo.dat>
\033[0m"
}
if [[ $# -gt 0 ]]
then
if [[ $1 == "-help" ]]
then
show_help
fi
if [[ $1 == "-crear" ]]
then
if test -n "$2"
then
archivo=$2
grupo=$(echo $archivo | sed 's/.dat//')
if test -f $archivo
then
#echo -e "\033[32m Creamos los usuarios en el grupo $grupo \033[0m"
if [[ $(ldapsearch -xLLL -b $LDAP cn=$grupo | grep -c 'ldap') -gt 0 ]]
then
echo -e "\033[31m No se crea el grupo, el grupo $grupo existe. \033[0m"
else
echo -e "\033[34m Primero creamos el grupo $grupo \033[0m"
#tomamos el ultimo gidNumbrer:
gidN=$(ldapsearch -xLLL -b $LDAP | grep gidNumber | cut -d':' -f2 | tail -1)
if [ -z "$gidN" ] #-z indica que la variable esta vacía
then
gidN=500
fi
gidN=$((gidN+1))
crear_grupo $grupo $gidN
fi
for((i=1;i<=$(wc -l $archivo | cut -d' ' -f1);i++))
do
usuario=$(head -$i $archivo | tail -1 | cut -d'@' -f1)
if [[ $(ldapsearch -xLLL -b $LDAP cn=$usuario | grep -c 'ldap') -gt 0 ]]
then
echo -e "\033[31m No se crea el usuario, $usuario existe. \033[0m"
else
#tomamos el ultimo gidNumbrer:
uidN=$(ldapsearch -xLLL -b $LDAP | grep uidNumber | cut -d':' -f2 | tail -1)
if [ -z "$uidN" ] #-z indica que la variable esta vacía
then
uidN=1000
fi
uidN=$((uidN+1))
echo -e "\033[34m Creamos el usuario $usuario \033[0m"
crear_usuario $usuario $uidN $grupo
fi
done
else
echo -e "\033[31m El archvio $archivo no existe \033[0m"
fi
else
echo -e "\033[31m Proporcionar el <archvio.dat> \033[0m"
show_help
fi
fi
if [[ $1 == "-borrar" ]]
then
if test -n "$2"
then
archivo=$2
grupo=$(echo $archivo | sed 's/.dat//')
if test -f $archivo
then
for((i=1;i<=$(wc -l $archivo | cut -d' ' -f1);i++))
do
usuario=$(head -$i $archivo | tail -1 | cut -d'@' -f1)
if [[ $(ldapsearch -xLLL -b $LDAP cn=$usuario | grep -c 'ldap') -gt 0 ]]
then
ldapdelete -x -w $password -D $LDAPadmin "uid=$usuario,ou=usuarios,$LDAP"
echo -e "\033[34m Borramos el usuario $usuario \033[0m"
else
echo -e "\033[31m El usuario $usuario no existe \033[0m"
fi
done
if [[ $(ldapsearch -xLLL -b $LDAP cn=$grupo | grep -c 'ldap') -eq 0 ]]
then
echo -e "\033[31m El grupo $grupo no existe. \033[0m"
else
#si el grupo no tiene usuarios borrarlo
NUMBERGID=$( ldapsearch -xLLL -D $LDAPadmin -w $password -b $LDAP cn=$grupo gidNumber | grep gid | cut -d':' -f2)
if [[ $(ldapsearch -xLLL -b $LDAP | grep -c $NUMBERGID) -eq 1 ]]
then
ldapdelete -x -w $password -D $LDAPadmin "cn=$grupo,ou=grupos,$LDAP"
echo -e "\033[34m Borramos el grupo $grupo sin usuarios \033[0m"
fi
fi
else
echo -e "\033[31m El archvio $archivo no existe \033[0m"
fi
else
echo -e "\033[31m Proporcionar el <archvio.dat> \033[0m"
show_help
fi
fi
else
show_help
fi
#listar y borrar los usuarios de un grupo entero