====== Examen Parcial - 75.08. Sistemas Operativos ====== **Cátedra:** Osvaldo Clua\\ **Fecha:** Primer recuperatorio - Segundo Cuatrimestre 2002\\ **Día:** 12/11/2002\\ **Tema:** UNIX Esta página está incompleta; podés ayudar completando el material. ===== Enunciado ===== Se tiene un directorio de Input con una serie de archivos a procesar. Programar un comando que grabe en un directorio de output un archivo con todos los registros de todos los archivos .txt del directorio de Input, considerando que: - Los registros deberán tener como segundo campo el nombre del archivo. - El archivo de output debe ser llamado logresumen y debe ser grabado en el mismo directorio del cual se obtiene la información a procesar. - El formato es igual para todos los archivos .txt y la longitud del registro es variable. El separador de campo es ":". - La cantidad de campos es igual en todos los archivos, pero se desconoce cual es esa cantidad. - Se deberán procesar sólo los archivos que tienen mas de 8 campos. Los que no cumplan esta condición se debe grabar un archivo de error logerror.txt. El comando debe comtemplar las siguientes opciones: - **-d** opción directorio de input, sin esta opción el directorio de input es el corriente. - **-a** opción todos, con esta opción se tendrán que barrer todos los subdirectorios del directorio de input buscando archivos .txt, en este caso el archivo de salida logresumen se graba en el directorio input "padre". Para esta opción el campo que contiene el nombre del archvio tendrá que ser con el path completo. - **-e** opción eliminar, se deberán eliminar todos los archivos que se procesan - **-f** opción final, con esta opción se deberá grabar al final del archivo logresumen los siguientes mensajes: - "Se procesaron n archivos" (donde n es la cantidad de archivos que se copiaron al logresumen). - "Se rechazaron n archivos" (donde n es la cantidad de archivos que se rechazaron y no se copiaron al logresumen) - Si el comando ejecuta con la opción **-e**, entonces agregar el mensaje: "Todos los archivos procesados fueron eliminados" ===== Resolución ===== #!/bin/bash RecorrerDir() { #$1 = Path que tengo que recorrer y en el que arranca posicionada la funcion for arch in * do if [ -d "$1/$arch" ] # Si arch es un directorio, entra en él (esto incluye . y ..) then cd "$1/$arch" RecorrerDir "$PWD" # Se llama a sí mismo (recursivamente else file=$(echo $arch | grep '.*\.txt$') # Si es ".txt" asigno nombre a file if [ "${file:-1}" != '1' ] # Me fijo si comando anterior asignó algo a file then ValidarArch "$file" # Valida (<8 campos) y procesa fi fi done } ValidarArch() { # Valida que el archivo tenga <8 campos y si el campo coincide con el filname (parametro) llama a AceptarReg #$1 = Nombre del archivo (incluye ".txt") IFS=' ' # Interanal File Separator ($* es su primer char). Separador de campos local rechazar='0' # Con local defino una variable invisible fuera del scop de la funcion scope. Rechaza o no el archivo for reg in `cat $1` # for variable in lista. cat va devolviendo línea a línea (registro). Recordar que $1 en esta funcion es $file (PRIMER parámetro de la recibido por la funcion, semejante a argv[1] con funcion main) do if [ "$rechazar" = '0' ] # Si no se rechaza (rechaza falso)... then declare -i cantcampos # declaro variable entera cantcampos. ¿let cantcampos=0 no da igual? cantcampos=$(echo $reg | grep -o ';' | wc -l) # cuenta campos: del reg, saca --only-matching con ';' y luego los cuenta ¿-l cuenta no líneas!? let cantcampos=$cantcampos+1 # cantcampos++ if (($cantcampos > 8)) then campo2=$(echo $reg | cut -d ';' -f 2) # hermoso comando cut, saca el field 2, campos separados por ';' if [ "$campo2" = "$1" ] # Compara 2do field con nombre de arch (param), pedido en ítem 1 enunciado then AceptarReg "$reg" # campo2==coincide con el filename, acepta fi else rechazar='1' # rechazo el registro fi fi done if [ "$rechazar" = '1' ] then RechazarArch "$1" # Si el archivo fue rechazado... else let aceptados=$aceptados+1 # aceptados++ fi if [ "$delete" = 'S' ] # Si fue elgida la opción -w (era -e), borra el archivo then rm $1 fi } AceptarReg() { #$1 = Registro echo $reg >> "$path/logresumen" # Append del registro (con su \n al final) } RechazarArch() { #$1 = Nombre del archivo echo "Archivo $1 rechazado" >> "$path/logerror" let rechazados=$rechazados+1 } # COMIENZO DEL SCRIPT path_anterior="$PWD" # Guardo el directorio corriente path="$PWD" # Guardo el directorio corriente while [ -n "$(echo $1 | grep '^-')" ] # mientras los parámetros comiencen con "-"... (excepto path, por eso el shift) do case $1 in # pruebo casos tomando "argv[1]". Notar que está definiendose un caso O EL OTRO (no varios al mismo tiempo). -d) path="$2" # si -d después viene el path, $2 shift;; -a) all='S';; # si la opción fue elegida, defino variable (all, recorrer subdirs) -w) delete='S';; # No me pregunten por que, pero con -e no entra aca -f) addtolog='S' # si la opción fue elegida, defino variable ("final", agrego de msgs a logs) declare -i aceptados=0 # Uso declare pq son enteros declare -i rechazados=0;; * ) echo 'USO: parcial [-d ] [-a] [-w] [-f]' # Si no se usan modificadores, mensaje y error (exit 1) exit 1;; esac shift done # fin del while, ahora sé qué tengo que hacer según el caso (mediante variables definidas cd "$path" # Voy al path (en el que ya estoy.... cof cof if [ "$all" = 'S' ] # recordar que eq es para comparar strings (al reves de Perl) then RecorrerDir "$path" # Si ALL, recorro todos, else # else sólo el actual for arch in * # for variable in lista. (variable "arch"). Va poniendo en arch cada elemento de lista (en este caso c/n d arch) do file=$(echo $arch | grep '.*\.txt$') # arch tiene el archivo actual del for, grep lo devuelve si termina en .txt if [ "${file:-1}" != '1' ] # Si el grep seteo la variable file con algo... OBS: [ -z $file ] debería ser == then ValidarArch "$file" # me fijo si valida (si tiene 8 campos). Si es así, procesa fi done fi