Jai un fichier de données avec plusieurs blocs de données entre des mots clés spécifiques (DATA
, END
). Jutilise awk
pour extraire les blocs de données dans des fichiers séparés, sur la base dun nom de fichier extrait dudit bloc. Étant donné que certains blocs de données partagent le même nom, je renomme chaque fichier de sortie avec un entier croissant si le fichier (« blockname
« ) existe déjà:
#cat input.file useless stuff1 DATA blockname1 data1 data1 END useless stuff2 DATA blockname2 data2 data2 END useless stuff3 DATA blockname1 data3 data3 END useless stuff4
Il y aurait trois fichiers de sortie attendus blockname1
, blockname2
et blockname1_1
(notez comment le dernier fichier a un entier qui lui est attribué)
#cat blockname1 DATA blockname1 data1 data1 END
(les autres en conséquence …)
Maintenant, le script suivant fonctionne comme je le souhaite:
awk "BEGIN { FS=" +" } ; \ /DATA/,/END/ \ { if ( $1 ~ /DATA/ ) \ { block=$2 ; i=0 ; file=block ;\ while ( system("test ! -e " file ) ) \ { i++ ; file=block"_"i ; print file } \ } ; \ print $0 > file \ } " \ input.file
Mon problème réside dans la boucle while
et son appel système:
Je mattendais à ce que system("test -e " file)
soit TRUE lorsque file
existe et quil soit FALSE si file
nexiste pas encore, cest-à-dire que la boucle while
ne démarre que si file
est présent et pour casser si (le nouveau) file
nexiste pas encore.
Cependant si jutilise system("test -e " file)
(et le rendre verbeux avec print file
), jai une boucle infinie du même nom avec un suffixe entier croissant et linverse system("test !-e " file)
donne le résultat souhaité.
Cela se comporte donc exactement à linverse de ce que jattendais.
Réponse
OK, jai pensé: le problème réside dans les différentes définitions de ce qui est VRAI et FAUX entre létat de sortie de test
et le while
condition de boucle dans awk
.
Une commande positive test
entraîne un code de sortie de 0
pour TRUE et un négatif dans 1
pour FALSE.
Cependant, dans awk
la boucle while
interprète 0
comme FALSE et 1
comme TRUE, donc exactement le contraire définition.
À titre dexemple:
awk "{ while ( 0 ) ; { print "0" } }" file
ne sera pas pro duce toute sortie, tandis que
awk "{ while (1) ; { print "1" } }" file
affichera une infinité de 1
s.
Bonnes pratiques est donc dêtre explicite dans une telle combinaison
while ( system("command") == 0 )
ou
while ( system("command") == 1 )
respectivement.
Donc dans mon cas
while ( system("test -e " file ) == 0 )
montre le comportement attendu.
Réponse
awk
system()
renvoie un statut de sortie de la commande que vous exécutez – 0 pour le succès et! = 0 sinon succès. Par exemple, vous pouvez essayer dexécuter:
v = system("date");
v sera 0
si vous exécutez:
v = system("dat");
v peut être 127 ou une valeur différente de 0, lerreur renvoyée par le système dexploitation si la commande dat est manquante ou introuvable.
Réponse
Si je vous comprends bien, le but est dextraire le contenu de input.file dans différents fichiers en évitant de perdre des blocs du même nom.
Si cest le cas, et, si le répertoire cible est toujours vide avant lextraction, alors il existe une meilleure solution (et plus rapide):
awk " /DATA/{ block=$2; n = blocks[block]++; file=block (n? "_" n: ""); } /DATA/,/END/{ print > file }" input.file
De cette façon awk ne « Vous navez pas besoin dexécuter un nouveau shell N fois juste pour tester si le fichier existe.
Notes:
- Il ny a pas besoin du bloc BEGIN, car le séparateur de champ de awk est déjà des espaces.
- Il ny a pas besoin de
"\"
à la fin des lignes, car le guillemet simple est déjà multiligne.
while
. Cependant, votre solution est assez soignée – merci, je préfère cela à mon objet encombrant. Le bloc BEGIN est un reste de mon format de fichier différent – jai oublié quil devient inutile dans mon exemple générique. Laisser la barre oblique inverse mépargnera quelques problèmes. Merci pour cela aussi. Mais vous avez parfaitement compris lintention du script ‘. Pourriez-vous expliquer la partien = blocks[block]++; file=block (n? "_" n: "")
plus en détail?blocks
qui est indexé par nom de bloc. Ex. Dans la première instance de"blockname1"
:blocks["blockname1"]
. Awk trouve cet index et parce quil nest pas ‘ trouvé suppose""
(également considéré comme zéro). Désormais, dans awk,n = var++
équivaut à{n=var;var++}
, doncn==""
etblocks["blockname1"]==1
.Enfin,file=block (n? "_" n: "")
est identique à{file=block;if(n!="") file+="_" n}
.