Tabla de Contenidos

Examen Parcial - 75.08. Sistemas Operativos

Cátedra: Osvaldo Clua
Fecha: Primera Oportunidad - Segundo Cuatrimestre 2007
Día: 06/11/2007

Esta página está incompleta; podés ayudar completando el material.

Enunciado

Expresiones Regulares

Se pide realizar un script que reciba por parámetro un número de patente de un rodado y muestre por salida estándar la marca junto con el nombre y número/s de teléfono de su dueño. ni contamos con un archivo llamado RODADOS.dat del que solo sabemos lo siguiente:

También contamos con un archivo llamado TELEFONOS.dat del que solo sabemos lo siguiente:

Importante: Solo se pueden utilizar los comandos grep, sed, wc y echo

PERL

Desarrollar un comando PERL denominado parcial.pl que permita procesar los archivos con novedades de compras y grabar el monto acumulado en un archivo de salida.

Se pide:

  1. Procesar todos los archivos de novedades de compras que encontramos en el directorio corriente y que cumplan con la máscara indicada en el primer parámetro de la invocación.
  2. Encontrar el monto de la compra según sea la posición indicada en el segundo parámetro de la invocación.
  3. Acumular el monto por artículo empleando una estructura hash y usando al “artículo” como clave y el monto como valor. El campo artículo es el campo inmediato siguiente al monto.
  4. Grabar la salida o mostrar el resultado por pantalla según lo indicado en el tercer parámetro de la invocación.

Input:

Validaciones a efectuar:

  1. Validar que se invoque al programa con al menos 2 parámetros, si hay error mostrar por pantalla un mensaje descriptivo y terminar el programa.
  2. No efectuar ningún tipo de validación especial de la máscara (Parámetro 1: Obligatorio: nombre del archivo de input o máscara) , emplearla tal cual se la recibe.
  3. Lo que se debe validar es que se obtenda al menos un archivo de novedades. Si ningún archivo cumple la condición, mostrar por pantalla el mensaje “sin novedades” y terminar el programa.
  4. Validar que la ubicación (Parámetro 2: Obligatorio : Ubicación del campo monto) sea un número >= 1 y < a la cantidad total de campos del resgistro de entrada. Esta validación efectuarla solo para el primer registro de un archivo. Si la ubicación queda fuera del rango, entonces mostrar un mensaje descriptivo y pasar al siguiente archivo.

Salida.

BASH

Se tiene un directorio donde diariamente se reciben archivos con las ventas de varias sucursales, los archivos son tel tipo vtasuc.txt, donde suc es el número de sucursal, (ej vta524.txt) el formato de los mismos es:

Fecha Operación (aaaammdd); Cod Producto ; Cod Cliente ; Cantidad ; Importe

Ej:

20060201;K13;457887;105;100;50

Se cuenta además con un archivo de sucursales (/etc/SUCURSALES.txt):

Cod Sucursal; Descripción Sucursar; Habilitada (S/N).

Se pide realizar un script que procese la información de las sucursales y de acuerdo a la opción ingresada muestre el resultado por salida standar.

-C <código de cliente> Mostrar monto total de las ventas de ese cliente (monto = importe x cantidad).

Validar para cada archivo que la sucursal exista en el archivo de sucursales y que este habilitada, si no es así rechazar el archivo(moverlo a un directorio de rechazados) e indicarlo por salida estándar. Validar también que la opción ingresada sea -C y que el codigo de cliente ingresado exista en el archivo de clientes /etc/clientes.txt. En caso de que los parámetros sean erróneos mostrar con ejemplo la correcta invocación del script.

Resolución

EXPRESIONES REGULARES

#!/bin/bash
 
###################################################################################
#HIPOTESIS Y PRECONDICIONES:                                                      #
#Un solo dueño puede tener varios teléfonos                                       #
#Los números de teléfono están listados en lineas separadas de CUIT coincidente   #
###################################################################################
 
# $1 = num de patente del rodado
# resultado: MARCA, NOMBRE, TEL/S
 
RODADO=`grep ^[^:]*:$1: RODADOS.dat`
CUIT=`echo "$RODADO"|sed s/'^[^:]*:[^:]*:[^:]*:[^:]*:'//|sed s/':.*$'//`
MARCA=`echo $RODADO|sed s/"^\([^:]*:\)\{6\}"//|sed s/":.*"//`
LINEASTELEFONOS=`grep "^\([^;]*;\)\{2\}$CUIT" TELEFONOS.dat`
NOMBRE=`echo $LINEASTELEFONOS|sed s/'^[^;]*;[^;]*;[^;]*;[^;]*;'//|sed s/';.*'//`
TELEFONOS=`grep "^\([^;]*;\)\{2\}$CUIT" TELEFONOS.dat|sed s/"^\([^;]*;\)\{5\}"//|sed s/";.*$"//`
 
# \E[34m = texto azul
# \E[30m = texto negro
 
# Uso -e para que me tome las secuencias de escape
 
echo -e "\E[34mMarca: \E[30m$MARCA"
echo -e "\E[34mNombre: \E[30m$NOMBRE"
echo -e "\E[34mTelefonos: \E[30m\n$TELEFONOS"

PERL

#!/bin/perl
 
#~ GonchuB
#~ 06-11-2007
#~ Perl
 
#~ Como el enunciado no dice de donde sacamos el articulo cuyo monto leemos del
#~ archivo de novedades, asumo que es un parametro obligatorio más.
if($#ARGV < 2) {
	die "El programa recibe al menos tres parametros (<mascara> <posicion del monto> <posicion del articulo>).\n";
}
 
#~ Leo los parámetros obligatorios.
my $mascara = $ARGV[0];
my $posicion_monto = $ARGV[1];
my $posicion_articulo = $ARGV[2];
 
#~ Defino los separadores de los archivos.
my $separador_novedades = ",";
my $separador_maestro = ":";
 
#~ My archivo maestro es fijo.
my $filename_maestro = "MaeArt";
 
#~ Abro mi archivo maestro en modo lectura.
open( MAESTRO, "$<filename_maestro" ) || die "No se pudo abrir el archivo $filename_maestro.\n";
my $archivo_maestro = join( "", <MAESTRO> );
my @lineas = split( "\n", $archivo_maestro );
my @registro;
 
#~ Variables que utilizare para crear el hash.
my $articulo;
my $descripcion;
my %productos_descripcion = ();
 
#~ Comienzo a generar my hash de articulo:descripcion en base al contenido
#~ del archivo maestro.
foreach $linea (@lineas) {
	@registro = split( $separador_maestro, $linea );
	$articulo = $registro[0];
	$descripcion = $registro[1];
 
	$productos_descripcion{$articulo} = $descripcion;
}
 
#~ Hash articulo:monto_acumulado.
my %productos_monto = ();
 
#~ Abro el directorio actual.
opendir( DIRECTORIO, "." ) || die "No se puede abrir el directorio actual.\n";
 
my $filename;
my $archivo;
my $cantidad_archivos = 0;
my $numero_linea = 1;
 
#~ Itero sobre la lista de archivos en mi directorio actual.
while( $filename = readdir(DIRECTORIO) ) {
 
	#~ Comparo cada archivo con la mascara que recibi.
	if( $filename =~ $mascara ) {
		$cantidad_archivos += 1;
		open( ARCHIVO, "<$filename" ) || die "No se pudo abrir el archivo $filename.\n";
		$archivo = join( "", <ARCHIVO> );
		@lineas = split( "\n", $archivo );
		foreach $linea (@lineas) {
			#~ Separo la linea en base al separador definido.
			@registro = split( $separador_maestro, $linea );
 
			#~ Solo valido las posiciones que recibi por parametro en el primer registro de mi archivo.
			if( $numero_linea == 1 ) {
				if ( ($posicion_monto > scalar(@registro)) || ($posicion_articulo > scalar(@registro)) ){
					print "Las posiciones recibidas son mayores a la cantidad de campos por registro en $filename.\n";
					next;
				}
			}
 
			#~ Obtengo el articulo y el monto del registor.
			$articulo = $registro[$posicion_articulo];
			$monto = $registro[$posicion_monto];
 
			#~ Si el articulo ya existe en el hash, le sumo el monto.
			#~ Si no existe, le asigno el monto leido.
			if( exists($productos_monto{$articulo}) ){
				$productos_monto{$articulo} += $monto;
			} else {
				$productos_monto{$articulo} = $monto;
			}
 
		}
	}
 
}
 
#~ Si ningun archivo cumple con la mascara, salgo del programa e informo la situacion.
if( $cantidad_archivos == 0 ) {
	die "No se encontro ningun archivo de novedades que cumpla con la mascara recibida.\n";
}
 
#~ Flag para indicar si recibi cuarto parametro o no.
my $recibi_output = 0;
 
#~ Si recibi cuarto parametro, abro el archivo indicado en modo append.
if( $#ARGV == 3 ) {
	$recibi_output = 1;
	open( OUTPUT, ">>$ARGV[3]" ) || die "No se pudo abrir el archivo $ARGV[3] en modo append.\n";
}
 
#~ Genero el output de mi programa. Ya sea en STDIN o en el archivo recibido.
foreach $clave (keys(%productos_monto)) {
	if( $recibi_output ) {
		print OUTPUT "$clave,$productos_monto{$clave}\n";
	} else {
		print "$clave:$productos_descripcion{$clave} - $productos_monto{$clave}\n";
	}
}

BASH

#!/bin/bash
 
###################################################################################################
# FI.UBA.AR 75.08
# Parcial 20071106_1 - Ejercicio BASH
# Resolucion 
# Autor: Maximiliano Milicich (mmilicich)
#
# HIPOTESIS Y PRECONDICIONES: 
# - Las cantidades y precios (importes) son ENTEROS (no manejamos aritmetica decimal)
# - Los archivos invalidos, por ahora no los movemos a ningun lado: solo emitimos el warning
# - El script se debe ejecutar "parado" en la ubicacion del mismo 
#   (working directory == ubicacion del script). Pues sino, no se encuentra el directorio "data" 
###################################################################################################
 
# Variables y Constantes:
ARCH_SUC="./SUCURSALES.txt"
ARCH_CLI="./clientes.txt"
DATADIR="./data"
 
# validamos los argumentos recibidos:
if [ $# -ne 2 ] ; then
	echo "$0 Error: Parametros incorrectos (Modo de uso $0 -C <codigo de cliente>)"
	exit 1
fi
if [ $1 != '-C' ] ; then
	echo "$0 Error: Parametros incorrectos (Modo de uso $0 -C <codigo de cliente>)"
	exit 1
fi
 
# Codigo de Cliente a procesar:
COD_CLI="$2"
 
# Validamos codigo de cliente:
if [ -z $(cat "$ARCH_CLI" | grep "$COD_CLI") ] ; then
	echo "$0 Error: Codigo de Cliente $COD_CLI invalido"
	exit
fi
 
# Procesamos los archivos de vtas de sucursales:
MONTO_TOTAL=0
 
IFS=$'\n' # Esto es para q el for separe por newline y no por blankspace
for ARCH_PATH in $(find "$DATADIR" -type f) ; do
 
	# Nos quedamos con el nombre del archivo (descartamos el path)	
	ARCH=$(basename "$ARCH_PATH")
 
	# Validamos q el formato del nombre sea correcto:
	if [ -z $(echo "$ARCH" | grep '^vta.*\.txt$') ] ; then
		echo "$ARCH formato de archivo invalido"
		continue
	fi
 
	# Nos quedamos con el codigo de Sucursal:
	SUC=$(echo "$ARCH" | sed 's:^vta\(.*\)\.txt$:\1:g')
 
	# Validamos que la sucursal exista y este habilitada:
	if [ -z "$(cat "$ARCH_SUC" | grep "^${SUC};[^;]*;S$")" ] ; then
		echo "Sucursal $SUC inexistente o inhabilitada."
		continue
	fi
 
	# Procesamos la data del archivo para nuestro cliente:
	# Filtramos los registros del cliente (con el grep)
	# Y para c/u emitimos <cantidad>*<precio> al array MONTO_ARCH (con el sed)
	# O sea, expresamos la cuenta del Monto Parcial...luego abajo calculamos el resultado
	MONTO_ARCH=$(cat "$ARCH_PATH" | grep "^[^;]*;[^;]*;${COD_CLI};[^;]*;[^;]*$" | sed "s:^.*;\([^;]*\);\([^;]*\)$:\1\*\2:g")
 
	# Si el array no tiene elementos, seguimos con otro archivo:
	if [ -z "$MONTO_ARCH" ] ; then
		continue
	fi
 
	# Procesamos los parciales (hacemos la cuenta) y acumulamos en el Total
	IFS=$'\n' # Esto es para q el for separe por newline y no por blankspace
	for LI in $(echo "$MONTO_ARCH") ; do
		MONTO_PARCIAL=$(($LI))
		MONTO_TOTAL=$(($MONTO_TOTAL+$MONTO_PARCIAL))
	done	
 
done # for
 
# FIN! Resultado final
echo "MONTO TOTAL FINAL PARA CLIENTE $COD_CLI: $MONTO_TOTAL"
 
exit