web-dev-qa-db-fra.com

Analyse de fichier texte par motif de colonne

Je me demandais s'il existe un moyen simple d'utiliser awk ou toute autre commande pour analyser un fichier texte tel qu'un fichier de quelque chose comme:

Step Temp Enthalpy
0    0    -368
100  1    -369
200  2    -372
300  6    -362
400  9    -365
SHAKE stats (type/ave/delta) on step 500
1 1.09  8.71362e-08
500  13   -358
600  15   -339
.
.
900  25   -306
SHAKE stats (type/ave/delta) on step 1000
1 1.09 7.06858e-08
1000 28  -306
.
.
.

pourrait imprimer une sortie de la colonne spécifique de nombres que je veux, comme uniquement les valeurs de température. Je sais que je pourrais faire quelque chose comme awk '{print $2}' pour les valeurs de température, mais mon fichier de données particulier contient d'autres lignes de données différentes avant et après le tableau 'Step Temp Enthalpy', ce qui le rend peu pratique. J'aimerais donc couper idéalement. avant et après cette information 'Step Temp Enthalpy' et imprimez uniquement la colonne de cette section du fichier de données dont j'ai besoin. Le fichier de données contient également cette ligne "SHAKE stats" toutes les 5 étapes, en plus d'une ligne après le "1 1.09 ... etc", que j'aimerais supprimer. Si je devais imprimer uniquement la colonne de température, j'aimerais qu'elle soit imprimée:

0
1
2
6
9
13
15
.
.
25
28
2
Jonathan Tran

Le modèle simple que vous avez est de supprimer la colonne 2 dans les lignes contenant/en commençant par les chiffres. La structure habituelle des commandes awk est /Pattern in current line/ { commands};. Les commandes entre accolades ne sont exécutées que si un motif est trouvé dans la ligne en cours. Nous pouvons donc faire:

$ awk '/^[[:digit:]]/{print $2}' input.txt
0
1
2
6
9
1.09
13
15
25
1.09
28

Pour supprimer également les nombres à virgule flottante, ajoutez un motif supplémentaire avec l'opérateur AND logique &&:

$ awk '/^[[:digit:]]/ && $0 !~ /[.]/ {print $2}' input.txt
0
1
2
6
9
13
15
25
28

Vous pouvez également utiliser un modèle de négation pour exclure les statistiques de secousse:

awk '!/^SHAKE/ && $0 !~ /[.]/ {print $2}' input.txt 

Pour répondre à la question dans le commentaire, vous pouvez combiner un motif d'intervalle (quelque chose comme /Pattern1/,/Pattern2/ {commands}) avec l'instruction if. Le modèle de plage exécute des commandes entre accolades uniquement pour les lignes correspondant à la plage, puis l'instruction if peut effectuer un filtrage supplémentaire. Dans ce cas particulier, vous pouvez simplement le combiner avec la solution précédente comme ceci:

$ awk '$0 == "Step Temp Enthalpy",0 { if( $0 ~ /^[[:digit:]]/ && $0 !~ /[.]/  ) print $2  }' input.txt

Le modèle $0 == "Step Temp Enthalpy",0 signifie le traitement de la ligne exacte Step Temp Enthalpy à 0, c'est-à-dire à la fin du fichier.

2
Sergiy Kolodyazhnyy

Voici une approche (éventuellement) plus simple basée sur la structure des données plutôt que sur la correspondance du contenu:

  • utilisez l'arithmétique modulo pour vérifier si nous sommes sur l'une des lignes SHAKE stats
  • si c'est le cas, relevez la ligne suivante avec getline et passez à la suite
  • sinon, affiche le deuxième champ

Alors

$ awk '!(NR%7) {getline; next} {print $2}' data
Temp
0
1
2
6
9
13
15


25
28
2
steeldriver