AWK, czy mógłby ktoś mi wytłumaczyć działanie skryptu usuwającego linijki pod pewnymi warunkami?

0
awk 'BEGIN {while (getline < "system_solvate.gro") {if ($1 ~ /SOL/ && $NF > 1.258 && $NF < 5.702) name[$1]=$1}} {if ($1 != name[$1]) print}' system_solvate.gro | tee after_SOL.gro

Skrypt usuwa linijki, w którym dany SOL ma wartość w ostatniej kolumnie pomiędzy 1.258, a 5.702
np. mamy dane
524SOL OW17658 10.091 6.953 1.578
524SOL HW117659 10.094 6.990 1.666
524SOL HW217660 10.162 6.997 1.531
525SOL OW17661 1.334 1.405 0.514
525SOL HW117662 1.293 1.420 0.599
525SOL HW217663 1.276 1.450 0.452
526SOL OW17664 5.312 10.906 6.363
526SOL HW117665 5.370 10.839 6.327
526SOL HW217666 5.311 10.889 6.457
527SOL OW17667 0.733 9.120 4.695
527SOL HW117668 0.668 9.106 4.626
527SOL HW217669 0.816 9.130 4.647

Po zadziałaniu skryptu usuwa się 525SOL - wystarczy, żeby choć jeden z trzech linijek 525SOL w ostatniej kolumnie był w tym zakresie i zostanie usunięty.
524SOL OW17658 10.091 6.953 1.578
524SOL HW117659 10.094 6.990 1.666
524SOL HW217660 10.162 6.997 1.531
525SOL OW17661 1.334 1.405 0.514
525SOL HW117662 1.293 1.420 0.599
525SOL HW217663 1.276 1.450 0.452
527SOL OW17667 0.733 9.120 4.695
527SOL HW117668 0.668 9.106 4.626
527SOL HW217669 0.816 9.130 4.647

Chciałbym wiedzieć jak ten skrypt działa krok po kroku

awk 'BEGIN {while (getline < "system_solvate.gro") {if ($1 ~ /SOL/ && $NF > 1.258 && $NF < 5.702) name[$1]=$1}} {if ($1 != name[$1]) print}' system_solvate.gro | tee after_SOL.gro

Na początku sprawdza czy jest linijka, jak się kończy plik to przerywa działanie programu. Potem sprawdza dopasowanie wyrażenia regularnego SOL i czy w ostatniej kolumnie wartość jest pomiędzy 1.258 5.702. Co do kolejnego name[$1]=$1 - czyli tablica o indeksie, np. SOL25 ma wartość SOL25. Potem jeśli if ($1 != name[$1]) print wartość z tablicy jest różna od indeksu z tablicy ???? to nic nie jest drukowane? Bo jest samo print bez żadnych $0 (cała linijka) czy coś takiego. I po co na początku wprowadzane jest słowo BEGIN?

2

Najpierw wykona się sekcja oznaczona jako BEGIN

BEGIN {while (getline < "system_solvate.gro") {if ($1 ~ /SOL/ && $NF > 1.258 && $NF < 5.702) name[$1]=$1}} 
  • BEGIN: oznacza, że cała sekcja wykona się przed właściwym przetwarzaniem tekstu.
  • while (getline < "system_solvate.gro") : wczytuje tekst po jednej linii. "system_solvate.gro" można zastąpić przez ARGV[1], żeby nie wpisywać nazwy pliku na stałe.
  • {if ($1 ~ /SOL/ && $NF > 1.258 && $NF < 5.702) name[$1]=$1}}: wykona się dla każdej wczytanej linii.
  • $1 ~ /SOL/: sprawdza czy pierwsza kolumna w wierszu zawiera "SOL "
  • $NF > 1.258 && $NF < 5.702: NF to liczba kolumn w wierszu, $NF to wartość ostatniej kolumny w wierszu. Warunek logiczny jest oczywisty
  • name[$1]=$1: tworzy tablicę asocjacyjną, gdzie kluczem i wartością jest ta sama wartość (de facto funkcjonuje to jak zbiór)

Potem skrypt awk będzie wykonywał się w normalnym trybie, tzn. parsował tekst po jednej linii (tak jakby została tam wstawiona pętla wczytująca tekst).

{if ($1 != name[$1]) print}
  • if ($1 != name[$1]: sprawdza czy wartość pierwszej kolumny wiersza nie znajduje się w tablicy asocjacyjnej. Z warunku z sekcji BEGIN wynika, że jeżeli wiersz w pierwszej kolumnie zawiera ciąg "SOL" a ostatniej wartość z zakresu (1.258, 5.702), to wartość jego pierwszej kolumny znajdzie się w tej tablicy.
  • print wypisze cały wiersz, o ile warunek był spełniony.

Reszta polecenia to:

  • system_solvate.gro podaje plik wejściowy dla awk.
  • | tee after_SOL.gro przekierowuje wyjście do komendy tee, która to zapisze wyjście do pliku after_SOL.gro, a także wypisze na standardowe wyjście.

1 użytkowników online, w tym zalogowanych: 0, gości: 1