Ejercicios Bash
Transcript of Ejercicios Bash
-
Ejercicios de programacion en shell bashDiseno y Administracion de Sistemas y RedesQuinto curso de Ingeniera Informatica, Universidad Rey Juan Carlos
Ejercicio 1
Tenemos un laboratorio de PCs donde cada ordenador tiene un fichero /etc/hosts que indica losnombres y direcciones IP de las demas maquinas.
El fichero sera similar a este:
212.128.4.203 a202e33.escet.urjc.es a202e33212.128.4.204 a202e34.escet.urjc.es a202e34212.128.4.209 a202e39.escet.urjc.es a202e39212.128.4.210 a202e40.escet.urjc.es a202e40212.128.4.211 gamma01.escet.urjc.es gamma01212.128.4.212 gamma02.escet.urjc.es gamma02212.128.4.213 gamma03.escet.urjc.es gamma03
Vamos a cambiar de direccion las maquinas gammaNN (donde NN es el numero del ordenador). Lanueva direccion de cada maquina sera
192.168.0.YY
donde YY= NN+40Haz un script de shell que muestre por salida estandar el nuevo fragmento de /etc/hosts.Para el fichero visto anteriormente, la salida sera:
192.168.0.41 gamma01.escet.urjc.es gamma01192.168.0.42 gamma02.escet.urjc.es gamma02192.168.0.43 gamma03.escet.urjc.es gamma03
Nota: No sabemos cuantos PCs hay. No podemos suponer que el fichero este ordenado. Puede haberhuecos en la numeracion (p.e. que exitan el gamma04 y gamma06 pero falte el gamma05)
Solucion
#!/bin/bashfichero_entrada=/etc/hostsmaquinas=$(grep gamma $fichero_entrada | cut -c44-45 )
for nn in $maquinasdo
yy=$(($nn+40))echo 192.168.0.$yy gamma$nn.escet.urjc.es gamma$nn
done
1
-
Ejercicio 2
Un profesor tiene las notas de los alumnos que se presentaron a un examen en un fichero de texto.Cada lnea esta compuesta por el login del alumno, un espacio y su calificacion, que siempre sera apto ono apto
jperez aptomgarcia no aptoasanche no aptomgome aptofcano apto
Desea un script de shell bash que enva un correo electronico a cada estudiante, con la siguienteinformacion:
Su nota, esto es, la lnea que le corresponda en el fichero anterior
El numero de estudiantes presentados, as como el de aprobados
Ejemplo: Al estudiante mgomezse le enva un correo similar a este:mgomez apto. Presentados: 5, Aprobados: 3
(Este correo lo leera un humano, as que no son relevantes los espacios, las mayusculas, etc)
Notas:
El script recibira en el argumento 1 de lnea de comandos el nombre del fichero con las notas
La direccion de cada estudiante es: [email protected]
En una maquina Unix, se puede enviar un correo mediante el comando mail, pasando:
El cuerpo del correo por la entrada estandar El destinatario del correo en el argumento 1 de lnea de comandos Si el script no recibe el nombre del fichero, debe mostrar un error y finalizar
Solucion
#!/bin/bashif test $# -ne 1then echo Uso: >&2
echo $0 fichero_de_notas>&2exit
fi
suspensos=$(cat $1 | grep "no apto" | wc -l)presentados=$(cat $1 | wc -l)aprobados=$(($presentados - $suspensos))
logins=$(cat $1 | cut -d -f1 )
for login in $loginsdo
su_nota=$(grep $login $1)estadisticas="Presentados: $presentados, Aprobados:$aprobados"echo $su_nota. $estadisticas | mail [email protected]
done
2
-
Observaciones:
echo Uso: >&2redirige la salida de echo a stderr
El filtro
grep apto
encaja tanto en la cadena apto como en la cadena no apto
El filtro
grep no
encaja tanto en la cadena no apto como en la cadena fcano
Ejercicio 3
Tenemos un directorio que contiene, entre otras cosas, fotos: ficheros con extension .jpg o .JPG. Lasfotos tienen mucha resolucion: Queremos reducirlas a 800x600 puntos y publicar la version reducida enun web. Para reducir el tamano podemos usar el comando
convert -geometry 800x600 origen destino
Para publicar en el web, basta copiar al directorio public html del home del usuario. Suponemos estedirectorio existente y con los permisos adecuados.Proceden de un sistema contaminado por un virus, as que hay ficheros que a pesar de su extension,no son imagenes jpeg sino ejecutables. Si son verdaderas imagenes el comando file mostrara un mensajesimilar a este.
imagen01.jpg: JPEG image data, EXIF standard 0.73, 10752 x 2048
Haz un script de shell bash que reciba como primer argumento el directorio, que compruebe cada fichero,que lo reduzca y publica si esta bien y que lo borre si esta contaminado, mostrando un mensaje parecidoa este:
imagen01.jpg CONTAMINADO. Se borra el fichero.imagen02.jpg ok. Reducida y publicado.imagen03.jpg ok. Reducida y publicado.
1 ficheros contaminados y borrados2 ficheros reducidos y publicados.
Solucion
#!/bin/bashif test $# -ne 1then echo Uso: >&2
echo $0 directorio>&2exit
fi
publicados=0contaminados=0
3
-
cd $1for i in ls *.[jJ][pP][gG]do
if file $i | grep -i jpegthen
convert -geometry 800x600 $i $HOME/public_html/$ipublicados=$(($publicados+1))echo $i ok. reducido y publicado
elserm $iecho $i CONTAMINADO. Se borra el ficherocontaminados=$(($contaminados+1))
fidoneecho $contaminados ficheros contaminados y borradosecho $publicados ficheros reducidos y publicados
Ejercicio 4
En cierta asignatura, los estudiantes deben realizar una pagina web. Todos los matriculados tienen cuentaen la maquina, aunque algunos nunca han llegado a abrir una sesion. A estos los llamaremos usuariosinactivos.Se desea hacer un script bash que haga una copia del web de todos los usuarios activos, que borre lacuenta de los usuarios inactivos y que muestre un pequeno informe de lo que esta haciendo.Los requisitos se detallan a continuacion:
1. Los usuarios matriculados tienen su home en el directorio al-03-04. Este es un fragmento del fichero/etc/passwd
jperez:x:10912:1009:Juan Perez,,,:/home/al-03-04/jperez:/bin/bash
mfernan:x:10913:1009:Manuel Fernandez,,,:/home/al-02-03/mfernan:/bin/bash
mgarcia:x:10914:1009:Maria Garcia ,,,:/home/al-03-04/mgarcia:/bin/bash
lruiz:x:10915:1009:Luis Ruiz ,,,:/home/al-03-04/lruiz:/bin/bash
2. Si un usuario es inactivo, el comando finger indicara Never logged in.Ejemplo:
finger jperez
Login: jperez Name: Juan Perez
Directory: /home/al-03-04/jperez Shell: /bin/bash
Never logged in.
No mail.
No Plan.
3. Las copias de las paginas web queremos guardarlas en
/var/tmp/mgarcia
/var/tmp/lruiz
Estos directorios no existen previamente.
4. Para hacer una copia de un web, usamos el comando wget del siguiente modo
wget -m http://localhost/~mgarcia
Esto copia el web de mgarcia en el directorio actual
5. El informe que muestra el programa debe ser parecido a este:
jperez. Usuario inactivo, se borra su cuenta.
mgarcia. Usuario activo, copiando su web en /var/tmp/mgarcia
lruiz. Usuario activo, copiando su web en /var/tmp/lruiz
4
-
Solucion
#!/bin/bash
alumnos=cat etc_passwd |grep al-03-04 | cut -d: -f1
for alumno in $alumnos
do
if finger $alumno | grep Never
then
echo $alumno. Usuario inactivo, se borra su cuenta
userdel $alumno
else
echo $alumno. Usuario activo, copiando su web en /var/tmp/$alumno
mkdir /var/tmp/$alumno
cd /var/tmp/$alumno
wget http://localhost/~$alumno
fi
done
Errores Frecuentes
finger $alumno | grep Never logged in #INCORRECTO!
(esto busca la cadena Never en el fichero logged y en el fichero in
correcto:finger $alumno | grep "Never logged in"
cat /etc/passwd | grep -v $alumno >/etc/passwd # INCORRECTO!
Cuando el shell interpreta la redireccion de salida de grep, trunca a 0 el fichero /etc/passwd.
cat /etc/passwd lee ese mismo fichero, provocando una condicion de carrera. (tal vez lea a tiempo,tal vez no)
incorrecto:wget http://localhost/~$alumno > /var/tmp/$alumno
Esto hace que los mensajes que wget saca por salida estandar vayan a un fichero de nombre/var/tmp/$alumno
Ejercicio 5
Tenemos en un sistema tipo UNIX a una serie de usuarios ya creados. Hemos visto que algunos de ellostienen su cuenta invadida por personas sin derecho a usar el equipo. Una cuenta esta invadida si en elhome del usuario hay un directorio llamado .rootkit
Este es un ejemplo del fichero de configuracion de usuarios (passwd)
jperez:x:10912:1009:Juan Perez,,,:/home/jperez:/bin/bash
mfernan:x:10913:1009:Manuel Fernandez,,,:/home/mfernan:/bin/bash
mgarcia:x:10914:1009:Maria Garcia ,,,:/home/mgarcia:/bin/bash
lruiz:x:10915:1009:Luis Ruiz ,,,:/home/lruiz:/bin/bash
Queremos un script que reciba como primer parametro el fichero de configuracion de usuarios y que paracada cuenta:
1. Si esta invadida, imprima un mensaje de alerta, la cancele (usando el comando correspondiente) ymueva el home del usuario al directorio /invadidos/
Puedes usar el comando test -e fichero que devuelve cierto si existe el fichero.
2. Si no esta invadida, nos diga desde que maquina se conecto el usuario la ultima vez. Para estopuede usarse el comando finger, que para usuario que han usado alguna vez la cuenta muestraalgo como esto:
5
-
bash$ finger mgarcia
Login: mgarcia Name:
Directory: /home/mgarcia Shell: /bin/bash
Last login Sun Jun 13 15:59 (CEST) on pts/14 from sumaquina.com
No mail.
No Plan.
(Observa que finger coloca un espacio entre la mayora de las palabras de su salida)
Solucion
#!/bin/bashfor usuario in $(cat $1 | cut -d: -f1)do
if test -e /home/$usuario/.rootkitthen
echo $usuario invadido!mv /home/$usuario /invadidosuserdel $usuario
elsedesde=$(finger $usuario| grep from |cut -d -f11)echo -n $usuario entro por ultima vez desde $desde
fidone
Ejercicio 6
Tenemos un directorio que contiene, entre otras cosas, scripts de shell. Se desea modificarlos, insertandoentre su primera lnea y segunda el copyright del autor y la fecha. Por ejemplo, el programa
#!/bin/bashecho hola mundo
Se quedara as:
#!/bin/bash# (c) Juan Garcia. You can redistribute this program under the terms of the GNU General Public License.# mar abr 12 16:05:20 CEST 2005echo hola mundo
Escribir un script de shell bash que haga esta tarea. Se usara por ejemplo de la siguiente forma:
pon_licencia $HOME/fuentes $HOME/licencia.txt
El primer parametro indica el directorio donde estan los fuentes. Todos llevan extension .sh (enminusculas).
La primera lnea de cada script debe respetarse, podra no ser exactamente #!/bin/bash. (Suge-rencia: siendo n el no de lneas del fichero, concatena la primera lnea con el texto nuevo con lasn-1 ultimas).
El mensaje de copyright es una unica linea de texto, que esta en el fichero que se pasa como segundoparametro. La fecha es la que proporciona el comando date. Ni el fichero con la licencia incluye laalmohadilla # ni la salida del comando lo muestra.
El script debe comprobar que recibe exactamente 2 parametros, que el primero es un directorio yel segundo un fichero legible. Si alguno de estos requisitos no se cumple, se muestra por stderr unmensaje de error especificando el problema. (Recuerda que para mostrar un mensaje por stderrbasta con redirigir texto a &2)
6
-
Solucion
#!/bin/bash
if [ $# -ne 2 ]
then
echo "uso: $0 directorio licencia " >&2
exit
fi
if ! [ -d $1 ]
then
echo "$1 no es un directorio" >&2
exit
fi
if ! [ -r $2 ]
then
echo "$2 no se puede leer" >&2
exit
fi
directorio=$1
licencia=$2
cd $directorio
for script in *.sh
do
n=$(cat $script | wc -l)
ene_menos_uno=$(($n - 1))
head -1 $script > aux
echo -n \# >> aux
cat $licencia >> aux
echo -n \# >> aux
echo $(date) >> aux
tail -$ene_menos_uno $script >>aux
mv aux $script
done
Errores Frecuentes
fecha=date #MAL!
Esto asigna a la variable fecha la cadena date. Si queremos que se ejecute el comando date, hayque usar $() o las comillas invertidas
cat $1 | grep *.sh # MUY MAL!
El comando para ver el contenido de un directorio es ls. Si queremos ver todos los ficheros deextension .sh, basta hacer ls *.sh
El comando cat recibe como argumento uno o mas ficheros. Si recibe uno, muestra su contenido porstdout. Si recibe mas de un fichero, muestra por stdout el contenido de uno tras otro, concatenados.
Cuando escribimos grep *.sh, el shell expande el asterisco. Supongamos que en el directorio actualtenemos los ficheros script_01.sh, script_02.sh y script_03.sh. El comando grep recibira estostres argumentos, exactamente igual que si hubieramos escrito
grep script_01.sh script_02.sh script_03.sh
Por tanto intenta buscar la cadena script 01.sh en los ficheros script 02.sh y script 03.sh
echo # > fichero #MAL
Todo lo que hay tras una almohadilla es un comentario. A menos que escapemos la almohadilla
echo \# >> fichero # Lleva almohadilla y fin de linea al fichero
o bien
echo # >> fichero # Lleva almohadilla y fin de linea al fichero
Tambien hay que tener en cuenta que echo muestra por su salida estandar el argumento que recibey un fin de lnea. Para omitir el fin de linea debemos pasar el parametro -n
7
-
echo -n # >> fichero # Lleva almohadilla al fichero, sin fin de lnea
Otra forma de evitar el fin de linea sera pasar varios argumentos a echo
echo \# $(cat $licencia) >> aux
8