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