sobre exportar globals con ^%GOGEN

La utilidad ^%GOGEN nos permite sacar a disco dentro de la red donde se encuentre el servidor de Caché GLOBALS o ficheros de la base de datos. Permite sacar uno o varios a la vez.

El formato que tiene si lo editamos es parecido a esto:

fichero exportado con ^%GOGEN
    Transferring files on Mar 30 2019 at 10:24 AM
    ^ALD(20190330

    ^ALD(20190330,"A",99730)
    20190330#20190330#20190330#392224##3020#0##1##1#1#N#500#1# 9:01# 9:01##TLP1####S##3#0#0###N#S##2#D##N###A######0#0#0#0#0#0#0#0#0#0#0#0#0#0###0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#######1###############################
    ^ALD(20190330,"A",99730,"CP",1)
    3#BONIFICACION TERMINAL#1###F#L#A#N###S#
    ^ALD(20190330,"A",99730,"CT")
    TER GZA EL#AV TRE 25#ZAMORA#49008#49#ZAMORA#P1#VALLADOLID#46P#1#49

Como se ve hay unas líneas en las que figuran los índices de los globals y otras que son lo datos. Los índices de un global pueden ser desde 0 a varios, lo mismo que los campos de datos.

problemas para obtener los datos en csv

Se trata de obtener ficheros csv que se puedan tratar por ejemplo en excel. Como los índices son variables por cada número de ellos tendremos distintos ficheros, así para el ejemplo de arriba obtendremos 3 ficheros. Uno para los registros que tienen 3 índices, otro para los de 4 y otro para los de 5.

En principio me pareció fácil hacerlo con 'bash' pero luego no resultó así. Hay varios problemas:

  • quería luego sacar los ficheros csv con una cabecera que indicara los campos que son índices de los que no. Y además cada fichero puede tener registros de cantidad variable de campos. Es decir. Dentro del fichero de 3 índices hay registros con 5 campos de datos, otros con 10 y otros con 116. La obtención de la cabecera correcta se complica. Quiero algo así:

    Index1;Index2;Index3;Data1;Data2;Data3;Data4;Data5;Data6;Data7;Data8;Data9;...
  • Y otro problema grande es cuando en el %GOGEN se exportan varios ficheros. Hay que localizar dentro de cada fichero el global que es. Quitar los "^" y los "()"

En resúmen. Si tengo que hacerlo ahora quizá empezaría con 'Python' o 'Go'. Lo que te ahorras en 'bash' es todo lo referente a apertura y escritura de ficheros que lo haces con un simple echo "registro" >> fichero

resultados

Al final obtengo los ficheros csv, varios uno por cada número de índices distintos tenga cada global ('global_ALD20190330-6.csv, global_ALD20190330-3.csv, global_ALD20190330-4.csv…​').

por ejemplo:

global_ALD20190330-5.csv
Index1;Index2;Index3;Index4;Index5;Data1;Data2;Data3;Data4;Data5;Data6;Data7;Data8;Data9;Data10;Data11;Data12;Data13;...
20190330;"A";99730;"CP";1;3;BONIFICACION TERMINAL;1;;;F;L;A;N;;;S;

Aquí al final el código. No olvidarse de dar permisos de ejecución con 'chmod +x xglobaltocsv.sh'

xglobaltocsv.sh
#!/usr/bin/env bash
# Función: dado un o varios GLOBAL exportados con ^%GOGEN de MUMPS
#			crea tantos ficheros csv como por índices tenga cada global
# Fecha creación: 30.03.2019
# Autor: Julio Briso-Montiano
# Versión: 1.0
# Detalle:
#   - se pide fichero exportado con %GOGEN
#   - se crean ficheros csv por cada global/índices
#   - se inserta cabecera en el csv del tipo Index1 Index2...Data1 Data2...
#

#
# petición de datos
if [ $# -eq 0 ]
  then
    echo "introduce global exportado con %GOGEN"
    exit
fi
echo -e "\nATENCIÓN: se van a borrar todos los ficheros de tipo global*.csv\n"
read -p "¿estás seguro? (s/n) " vamos
if [[ $vamos != "s" ]]
then
	echo "abortado"
	exit
fi

#
# variables para trabajar
file=$1
sepcsv=";"
global=""
isindex=""
detectedglobal=""
declare -A fic
rm global-*.csv

#
# leemos línea a línea
while IFS= read -r line
do
	#
	# primero tenemos que detectar cuándo es una línea
	# de índices y cuándo es de datos.
	# cuidado que puede haber campos de datos del tipo
	# ^ALD(x,y,z que parecen de índices
	if [[ "${line:0:18}" == "Transferring files" ]]
	then
		detectedglobal="nextline"
		continue
	fi
	if [[ $detectedglobal == "nextline" ]]
	then
		global="${line//[()$'\r'^]/}"
		echo "global found "$global
		detectedglobal="jump"
		continue
	fi
	if [[ $detectedglobal == "jump" ]]
	then
		detectedglobal=""
		isindex=1
		continue
	fi
	#
	# now we have a global to work on
	# first el de índices
	line="${line//$'\r'/}"
	if [[ $isindex -eq 1 ]]
	then
		isindex=0
		regindex="${line#*(}"
		comas="${regindex//[^,]}"
		indices="${#comas}"
		((indices+=1))
		# hasta aquí para averiguar los índices
		regindex="${regindex//[,)]/$sepcsv}"
		continue
	fi
	# registro de datos que unimos con el de índices y grabamos
	if [[ $isindex -eq 0 ]] && [[ $indices > 0 ]]
	then
		isindex=1
		ficactual=${global}"_"${indices}
		sepas="${line//[^#]}"
		campos="${#sepas}"
		((campos+=1))
		if [[ ${campos} -gt ${fic[$ficactual]} ]]
		then
			fic[$ficactual]=$campos
		fi
		# hasta aquí para averiguar el número máximo de campos para
		# ese global/índice
		regdata="${line//#/$sepcsv}"
		finalreg="${regindex}""${regdata}"
		echo $finalreg >> "global-"$global"_"$indices".csv"
	fi
done <"$file"

#
# insertamos cabecera de nombres
# por cada fichero obtenido
for tipos in "${!fic[@]}"
do
	campos=${fic[$tipos]}
	indices="${tipos#*_}"
	cab=""
	for ((i=1; i<=$indices; i++))
	do
		cab=$cab"Index"$i"\t"
	done
	for ((i=1; i<=$campos; i++))
	do
		cab=$cab"Data"$i"\t"
	done
	# no POSIX
	sed -i "1i"$cab "global-"$tipos".csv"
	echo -e $cab > borrame.txt && cat "global-"$tipos".csv" >> borrame.txt && mv borrame.txt "global-"$tipos".csv"
	sed -i 's/;/\t/g' global-$tipos".csv"
	echo "Generado fichero global-"$tipos".csv"
done

Tags: MUMPS, bash