Ejercicios Bash

8
Ejercicios de programaci´ on en shell bash Dise˜ no y Administraci´ on de Sistemas y Redes Quinto curso de Ingenier´ ıa Inform´ atica, Universidad Rey Juan Carlos Ejercicio 1 Tenemos un laboratorio de PCs donde cada ordenador tiene un fichero /etc/hosts que indica los nombres y direcciones IP de las dem´ as m´ aquinas. El fichero ser´ a similar a este: 212.128.4.203 a202e33.escet.urjc.es a202e33 212.128.4.204 a202e34.escet.urjc.es a202e34 212.128.4.209 a202e39.escet.urjc.es a202e39 212.128.4.210 a202e40.escet.urjc.es a202e40 212.128.4.211 gamma01.escet.urjc.es gamma01 212.128.4.212 gamma02.escet.urjc.es gamma02 212.128.4.213 gamma03.escet.urjc.es gamma03 Vamos a cambiar de direcci´ on las m´ aquinas gammaNN (donde NN es el n´ umero del ordenador). La nueva direcci´ on de cada m´ aquina ser´ a 192.168.0.YY donde YY= NN+40 Haz un script de shell que muestre por salida est´ andar el nuevo fragmento de /etc/hosts. Para el fichero visto anteriormente, la salida ser´ ıa: 192.168.0.41 gamma01.escet.urjc.es gamma01 192.168.0.42 gamma02.escet.urjc.es gamma02 192.168.0.43 gamma03.escet.urjc.es gamma03 Nota: No sabemos cu´ antos PCs hay. No podemos suponer que el fichero est´ e ordenado. Puede haber huecos en la numeraci´ on (p.e. que exitan el gamma04 y gamma06 pero falte el gamma05) Soluci´ on #!/bin/bash fichero_entrada=/etc/hosts maquinas=$(grep gamma $fichero_entrada | cut -c44-45 ) for nn in $maquinas do yy=$(($nn+40)) echo 192.168.0.$yy gamma$nn.escet.urjc.es gamma$nn done 1

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