appel système awk avec effet inversé

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.

Commentaires

  • Eh bien, mon problème était plus dans la compréhension du comportement  » impair  » de la condition 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 partie n = blocks[block]++; file=block (n? "_" n: "") plus en détail?
  • Lalgorithme utilise un tableau: 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++}, donc n=="" et blocks["blockname1"]==1.Enfin, file=block (n? "_" n: "") est identique à {file=block;if(n!="") file+="_" n}.
  • Je nétais pas ‘ t même conscient quune chaîne est une variable dindexation valide et de cette instruction if réduite – très utile, merci encore. Je ‘ m attristé Je ne peux pas vous donner la  » réponse acceptée  » ici: malgré moi va adopter cette approche car elle remplit ma tâche initiale, elle ne ‘ t répondre à la question ci-dessus (interprétation de la condition dans la boucle while) – cela irait à lencontre de ma compréhension de ces sites Q & Un système. Pourtant, jai beaucoup appris – merci encore.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *