Create a target file using the contents of a source file by adding strings to it

Viewed 59

I have a source file.txt that i need to be generated and (his content) reformated in a target file.

Here is my source file :

TABLE;APGFPOLI;
Contrat;CHAR(16);Numéro du contrat
Libelle;CHAR(30);Libellé du contrat
DtCreation;CHAR(8);Date de création
DtMaj;CHAR(8);Date de dernière MAJ
DtEffet;CHAR(8);Date d'effet adhésion
MotifAdh;CHAR(2);Motif d'adhésion
DtRadiation;CHAR(8);Date de radiation
DtEnrRad;CHAR(8);Date enregistrement radiat
MotifRad;CHAR(2);Motif de radiation
MtPrime;Numérique 8.2;Montant prime d'origine
DtEffetSusp;CHAR(8);Date d'effet de suspension
DtFinSusp;CHAR(8);Date de fin de suspension
MotifSusp;CHAR(2);Motif de suspension
DestBord;CHAR(1);Destinataire du bordereau
CdDest;CHAR(5);Code du destinataire
NivRupBord;CHAR(1);Niveau rupture bordereau
BordCETIP;CHAR(1);Bordereau CTIP
EnvBordNom;CHAR(1);Envoi bordereau nominatif
Indice;CHAR(2);Indice appliqué
Echeance;CHAR(2);Echéance de l'indice (MM)
Effectif;CHAR(5);Effectif
CdRegr;CHAR(3);Code regroupement 1
CdGroupe;CHAR(3);Code regroupement 2
Periodicite;CHAR(1);Périodicité
Terme;CHAR(1);Terme
Produit;CHAR(6);Code produit affecté
Inspecteur;CHAR(5);Inspecteur
CleInsp;CHAR(1);Clé inspecteur
Filler;CHAR(6);Filler

And this the output that i want :

01 APGFPOLI.                       

   * Numéro du contrat              

     05 Contrat PIC X(16).        

   * Libellé du contrat             

     05 Libelle PIC X(30).        

   * Date de création             

     05 DtCreation PIC X(8).      

   * Date de dernière MAJ              

     05 DtMaj PIC X(8).           

   * Date d'effet adhésion           

     05 DtEffet PIC X(8).         

   * Motif d'adhésion               

     05 MotifAdh PIC X(2).         

   * Date de radiation           

     05 DtRadiation PIC X(8).     

   * Date enregistrement radiat     

     05 DtEnrRad PIC X(8).        

   * Motif de radiation             

     05 MotifRad PIC X(2).        

   * Montant prime d'origine   

     05 MtPrime PIC 9(8).v9(2)..   

   * Date d'effet de suspension  

     05 DtEffetSusp PIC X(8).     

   * Date de fin de suspension     

     05 DtFinSusp PIC X(8).       

   * Motif de suspension           

     05 MotifSusp PIC X(2).       

   * Destinataire du bordereau      

     05 DestBord PIC X(1).        

   * Code du destinataire             

     05 CdDest PIC X(5).          

   * Niveau rupture bordereau     

     05 NivRupBord PIC X(1).      

   * Bordereau CTIP                

     05 BordCETIP PIC X(1).       

   * Envoi bordereau nominatif    

     05 EnvBordNom PIC X(1).      

   * Indice appliqué                   

     05 Indice PIC X(2).          

   * Echéance de l'indice (MM).      

     05 Echeance PIC X(2).        

   * Effectif                       

     05 Effectif PIC X(5).        

   * Code regroupement 1              

     05 CdRegr PIC X(3).          

   * Code regroupement 2            

     05 CdGroupe PIC X(3).        

   * Périodicité                 

     05 Periodicite PIC X(1).     

   * Terme                             

     05 Terme PIC X(1).           

   * Code produit affecté            

     05 Produit PIC X(6).         

   * Inspecteur                   

     05 Inspecteur PIC X(5).      

   * Clé inspecteur                  

     05 CleInsp PIC X(1).         

   * Filler                           

     05 Filler PIC X(6). 

      

So being a newbie in the unix shells, what i did is using sed to do that. But when i used sed with the -i option it changed my source file and i ABSOLUTELY do not want that. So i removed it, but the problem now is that my output is not like the one that i want.

Here is my shell :

#!/bin/bash

#Fichier Source
fichier="APGFPOLI.des.txt"

champAdd="05 "
firstAdd="01 "

if [[ -f "$fichier" ]]
then
    
    # read it
    sed  "1s/TABLE/$firstAdd /" $fichier |sed  's/CHAR/PIC X/' $fichier | sed -E '/Numérique/s/;Numérique\s+([^;]*)/;PIC 9(\1)/' $fichier | while IFS=';' read -r nomChamp format libelle
    do
        echo \* $libelle
        echo $nomChamp $format.
    done > test.txt
fi

And here is the output that i have :

*
TABLE APGFPOLI.
* Numéro du contrat
Contrat CHAR(16).
* Libellé du contrat
Libelle CHAR(30).
* Date de création
DtCreation CHAR(8).
* Date de dernière MAJ
DtMaj CHAR(8).
* Date d'effet adhésion
DtEffet CHAR(8).
* Motif d'adhésion
MotifAdh CHAR(2).
* Date de radiation
DtRadiation CHAR(8).
* Date enregistrement radiat
DtEnrRad CHAR(8).
* Motif de radiation
MotifRad CHAR(2).
* Montant prime d'origine
MtPrime PIC 9(8.2).
* Date d'effet de suspension
DtEffetSusp CHAR(8).
* Date de fin de suspension
DtFinSusp CHAR(8).
* Motif de suspension
MotifSusp CHAR(2).
* Destinataire du bordereau
DestBord CHAR(1).
* Code du destinataire
CdDest CHAR(5).
* Niveau rupture bordereau
NivRupBord CHAR(1).
* Bordereau CTIP
BordCETIP CHAR(1).
* Envoi bordereau nominatif
EnvBordNom CHAR(1).
* Indice appliqué
Indice CHAR(2).
* Echéance de l'indice (MM)
Echeance CHAR(2).
* Effectif
Effectif CHAR(5).
* Code regroupement 1
CdRegr CHAR(3).
* Code regroupement 2
CdGroupe CHAR(3).
* Périodicité
Periodicite CHAR(1).
* Terme
Terme CHAR(1).
* Code produit affecté
Produit CHAR(6).
* Inspecteur
Inspecteur CHAR(5).
* Clé inspecteur
CleInsp CHAR(1).

As you can see, first thing is that my sed changes are not here, and the output is missing the last line of my source file. I am now stuck thinking of a way to achieve what i want.

2 Answers

If you specify an input file ($fichier) for sed it will not read from stdin, so the result of the first sed command is ignored when you use

sed  "1s/TABLE/$firstAdd /" $fichier |sed  's/CHAR/PIC X/' $fichier | ...

use

    sed  "1s/TABLE/$firstAdd /" "$fichier" |sed  's/CHAR/PIC X/' | sed -E '/Numérique/s/;Numérique\s+([^;]*)/;PIC 9(\1)/' | ...

or specify multiple commands for one invocation of sed

    sed -E -e  "1s/TABLE/$firstAdd /"  -e 's/CHAR/PIC X/' -e '/Numérique/s/;Numérique\s+([^;]*)/;PIC 9(\1)/' "$fichier" | ...

It might be easier to implement this with awk.

awk -F ';' '$1=="TABLE" && $3=="" {printf "01 %s.\n\n", $2; next} {sub(/CHAR/,"PIC X", $2);printf "   * %s.\n\n     05 %s %s.\n\n", $3, $1, $2;}' APGFPOLI.des.txt > test.txt

Explanation:

  • -F ';' field separator ;
  • $1=="TABLE" && $3=="" detect TABLE line. Alternative: Check for record number 1 (FNR==1)
  • printf "01 %s.\n\n", $2 formatted output
  • next Skip further processing of this record. Avoids a condition for the next commands.
  • sub(/CHAR/,"PIC X", $2) replace CHAR
  • printf " * %s.\n\n 05 %s %s.\n\n", $3, $1, $2 formatted output.

If necessary you could add variables for 01 and 05.

awk -F ';' -v 'champAdd=05' -v 'firstAdd=01' '$1=="TABLE" && $3=="" {printf "%s %s.\n\n", firstAdd, $2; next} {sub(/CHAR/,"PIC X", $2);printf "   * %s.\n\n     %s %s %s.\n\n", $3, champAdd, $1, $2;}' APGFPOLI.des.txt > test.txt

The awk solution above does not replace the string Numérique ....

The following command includes this but works only with GNU awk because of the gensub command. Without this command it would require more code to do the replacement in case the numbers after Numérique can vary. For constant numbers it would be easy to replace one exact string with another using one sub command.

awk -F ';' -v 'champAdd=05' -v 'firstAdd=01' '$1=="TABLE" && $3=="" {printf "%s %s.\n\n", firstAdd, $2; next} {sub(/CHAR/,"PIC X", $2);$2=gensub(/Numérique ([0-9]*)\.([0-9]*)/,"PIC 9(\\1).v9(\\2)",1,$2);printf "   * %s.\n\n     %s %s %s.\n\n", $3, champAdd, $1, $2;}' APGFPOLI.des.txt > test.txt

(You can use the same gensub command in the script version without variables champAdd etc.)

This might work for you (GNU sed):

sed -E '1{s/.*;(.*);/01 \1./;b}
        s/(.*);CHAR(.*);(.*)/\n   * \3\n\n     05 \1 PIC X\2./
        s/(.*);Numérique (.*)\.(.*);(.*)/\n   * \4\n\n     05 \1 PIC 9(\2).v9(\3)./' file

Pattern match and format the back references to the required output.

Related