GNU/Linux >> Linux Esercitazione >  >> Linux

Awk da linee diverse?

Sto cercando di estrarre alcuni dati da un file che si aggiorna costantemente e ho capito come filtrare due stringhe con grep. L'output è il seguente:

!    total energy              =   -9744.24963670 Ry
     convergence has been achieved in 188 iterations
!    total energy              =   -9744.30001681 Ry
     convergence has been achieved in 140 iterations
!    total energy              =   -9744.33953891 Ry
     convergence has been achieved in 155 iterations
!    total energy              =   -9744.36584201 Ry
     convergence has been achieved in 164 iterations
!    total energy              =   -9744.37925372 Ry
     convergence has been achieved in 154 iterations
!    total energy              =   -9744.39185493 Ry
     convergence has been achieved in 153 iterations
!    total energy              =   -9744.39836617 Ry
     convergence has been achieved in 160 iterations

Ora quello che vorrei fare è estrarre da queste righe i numeri come segue:
dalla riga che inizia con ! Voglio il numero nella colonna n. 5 e dalla riga successiva nell'output di grep voglio il numero nella colonna n. 6.
Successivamente vorrei che questi numeri fossero scritti in un file separato come due colonne separate come:

188 -9744.24963670
140 -9744.30001681
155 -9744.33953891
164 -9744.36584201

Stavo pensando che un approccio con awk scorrendo tutti questi risultati grep e poi guardando le righe dispari e stampando la colonna 5 e poi per le righe pari stampando la colonna 6. Ma non ho idea di come farlo.

Ho provato a estrarre i singoli risultati in variabili separatamente:

var1=$(grep '!' input.file | awk '{print $5}')

e

var2=$(grep 'convergence has been achieved' input.file | awk '{print $6}')

e poi ho provato a scriverli in un file come:

echo $var1 $var2 > data.dat

Tuttavia il risultato non è quello previsto:

188                                                                                                                                                                                             
140
155
164
154
153
160 -9744.24963670
-9744.30001681
-9744.33953891
-9744.36584201
-9744.37925372
-9744.39185493
-9744.39836617

Non so come scriverli nella forma che ho menzionato sopra. Inoltre siccome il file è costantemente aggiornato immagino il pezzo di codice da combinare con un ciclo while e end condition (so come fare quest'ultima parte)

Spero di averlo spiegato chiaramente!

Risposta accettata:

Awk soluzione:

awk 'v && NR==n{ print $6,v > "result.txt" }/^!/{ v=$5; n=NR+1 }' file
  • <condition1> { <statement> ... }<condition2>{ <statement> ... } – le condizioni con le rispettive dichiarazioni verranno valutate consecutivamente

  • /^!/{ v=$5; n=NR+1 } – all'incontro con la riga che inizia con ! – cattura il valore del 5° campo $5 e pianifica il numero di riga successivo NR+1 (assegnando alla variabile n )

  • v && NR==n – se abbiamo il 1° numero cruciale v e il numero di registrazione corrente NR è il "numero di riga successivo" necessario n – stampa i valori nel file result.txt

Il result.txt contenuto del file:

188 -9744.24963670
140 -9744.30001681
155 -9744.33953891
164 -9744.36584201
154 -9744.37925372
153 -9744.39185493
160 -9744.39836617

Linux
  1. Come catturare un file da Awk?

  2. Lettura di righe da un file con Bash:per vs. Mentre?

  3. Conta righe, parole e caratteri da un file in Linux

  4. Comando wc Linux

  5. Stampa l'ultima riga di un file, dalla CLI

Come rimuovere le righe da un file usando il comando Sed

Disegna a caso un certo numero di righe da un file di dati?

Eliminazione di righe specifiche da un file nella riga di comando di Linux

Rimuovi le righe vuote in un file di testo tramite grep

Elenca le righe di un solo file in DIFF

estrarre le linee dal basso fino alla corrispondenza regex