Comment lire un fichier de configuration qui a la définition de longueur fixe pour imprimer le gros fichier en conséquence

J’ai le fichier de configuration customer.cfg qui a 2 champs: Description et longueur de colonne comme ci-dessous:

ID ; 10 First Name ; 20 Last Name ; 20 

J’ai aussi un énorme fichier de données customer.dat qui contient les données que je veux lire comme vous pouvez le voir ci-dessous:

 1234567890John Armless 9 Eric Clapton 10 Roger Waters 

Je voudrais saisir NUMÉRO DE LIGNE, CONFIG_FILE_NAME et DATA_FILE_NAME et awk devrait pouvoir imprimer les données du gros fichier en fonction de la définition du format du fichier .cfg:

Par exemple:

Exemple 1

 Input: 2,customer.cfg,customer.dat Outputs: DataFileName: customer.dat Line: 2 ID:9 First Name:Eric Last Name:Clapton 

Exemple 2:

 Input:all,customer.cfg,customer.dat Outputs: DataFileName: customer.dat Line: 1 ID:1234567890 First Name:John Last Name:Armless DataFileName: customer.dat Line: 2 ID:9 First Name:Eric Last Name:Clapton DataFileName: customer.dat Line: 3 ID:10 First Name:Roger Last Name:Waters 

J’ai la même chose pour d’autres fichiers tels que products.cfg & products.dat, etc. mais toujours en suivant les mêmes normes que celles décrites ci-dessus. Je veux donc que quelque chose de générique suffise pour être utilisé avec d’autres fichiers.

 Considerations: - I want a solutions that uses AWK & printf - I can't install anything on this server. - My server is running AIX 

Vous pouvez essayer le script suivant: (Si vous Gnu Awk version 4, vous pouvez simplifier le script en utilisant FIELDWIDTHS au lieu d’appeler des substr )

 #! /bin/bash lineno=all cfgfile="customer.cfg" datfile="customer.dat" awk -v line="$lineno" -f p.awk FS=";" "$cfgfile" "$datfile" 

p.awk est:

 NR==FNR { a[++i]=$2 next } line=="all" || FNR==line{ print "DataFileName: " FILENAME print "Line "FNR id=getField(1,a[1]) fn=getField(1+a[1],a[2]) ln=getField(1+a[1]+a[2],a[3]) print "ID:"id print "First Name: "fn print "Last Name: "ln } function getField(a,b,str) { str=substr($0,a,b) sub(/^[[:blank:]]+/,"",str) sub(/[[:blank:]]$/,"",str) return str } 

avec sortie:

 DataFileName: customer.dat Line 1 ID:1234567890 First Name: John Last Name: Armless DataFileName: customer.dat Line 2 ID:9 First Name: Eric Last Name: Clapton DataFileName: customer.dat Line 3 ID:10 First Name: Roger Last Name: Waters 

Voici un moyen plus générique de le gérer sans coder en dur les noms de colonnes. Cela permettra d’exécuter le code sur différents fichiers.

 NF > 1 { colwidth[FNR]=$2 colname[FNR]=$1 ++colcount } NF < 2 { if(line=="all" || FNR==line) { printf("DataFileName: %s\n",FILENAME) printf("Line %d\n",FNR) nextcol=1 for(eachcol=1; eachcol <= colcount; eachcol++ ) { printf("%s : %s\n",colname[eachcol],substr($0,nextcol,colwidth[eachcol])) nextcol+=colwidth[eachcol] } } } 

Voici ce que j'obtiens quand je lance le code ci-dessus. J'ai enregistré le code sous /tmp/p.awk.

 **awk -v line=2 -f /tmp/p.awk -F";" /tmp/customer.cfg /tmp/customer.dat** DataFileName: /tmp/customer.dat Line 2 ID : 9 First Name : Eric Last Name : Clapton **awk -v line=all -f /tmp/p.awk -F";" /tmp/customer.cfg /tmp/customer.dat** DataFileName: /tmp/customer.dat Line 1 ID : 1234567890 First Name : John Last Name : Armless DataFileName: /tmp/customer.dat Line 2 ID : 9 First Name : Eric Last Name : Clapton DataFileName: /tmp/customer.dat Line 3 ID : 10 First Name : Roger Last Name : Waters 

@ Håkon Hægland J’ai changé un peu votre code pour le rendre suffisamment générique pour que je puisse maintenant l’utiliser pour tous les fichiers * .dat * .cfg que j’ai ici.

 NR==FNR { a[++i]=$2 b[i]=$1 next } line=="all" || FNR==line{ print "DataFileName: " FILENAME print "Line: "FNR linePos=1 for (j=1;j<=i;j++){ print b[j]":" getField(linePos,a[j]) linePos+=a[j] } print "\n" } function getField(a,b,str) { str=substr($0,a,b) sub(/^[[:blank:]]+/,"",str) sub(/[[:blank:]]$/,"",str) return str } 

Merci encore.