Jak odjąć wiersze (linie) za pomocą AWK

9

Próbuję wymyślić, jak mogę użyć AWK do odejmowania linii. Na przykład wyobraź sobie, że plik wejściowy to:

30
20

Dane wyjściowe będą:

10

Teraz jako test próbuję obliczyć kolumnę pamięci „Używane” z:

$ cat /proc/meminfo

W tej chwili napisałem to:

$ grep -P 'MemTotal|MemFree' /proc/meminfo | \
    -- Here comes the calculation using AWK

Próbowałem następujące:

$ grep -P 'MemTotal|MemFree' /proc/meminfo | \
    awk '{print $2}' | awk '{$0-s}{s=$0} END {print s}' 

Ale to daje mi tylko ostatni wiersz danych.

Znalazłem działające rozwiązanie, ale wątpię, aby było najbardziej optymalne. Całe moje doświadczenie w kodowaniu mówi mi, że twarde kodowanie liczby wierszy jest okropne: P

$ grep -P 'MemTotal|MemFree' /proc/meminfo | \
    awk '{print $2}' | awk 'NR == 1{s=$0} NR == 2 {s=s-$0} END {print s}'
Dylan Meeus
źródło
Co chciałbyś zrobić z N rzędami? Czy końcowy wynik powinien być line1_$2 - line2_$2 - lineN-$2? Czy chcesz tylko odjąć pierwsze dwa kolejne wiersze?
terdon

Odpowiedzi:

9

Można też to zrobić przy użyciu awk, pasteoraz bc. Uważam, że takie podejście jest łatwiejsze do zapamiętania, a składnia awkzawsze wymaga ode mnie sprawdzenia w celu potwierdzenia.

UWAGA: Podejście to ma tę zaletę, że może konkurować z wieloma liniami wyniku, odejmując liczby 2, 3, 4 itd. Od liczby 1.

$ grep -P 'MemTotal|MemFree' /proc/meminfo | \
    awk '{print $2}' | paste -sd- - | bc
7513404

Detale

Powyższe służy awkdo wybrania kolumny zawierającej liczby, które chcemy odjąć.

$ grep -P 'MemTotal|MemFree' /proc/meminfo | \
    awk '{print $2}'
7969084
408432

Następnie używamy pastedo połączenia tych 2 wartości wartości i dodania między nimi znaku minus.

$ grep -P 'MemTotal|MemFree' /proc/meminfo | \
    awk '{print $2}'| paste -sd- -
7969084-346660

Gdy przekażemy to bc, wykonuje obliczenia.

$ grep -P 'MemTotal|MemFree' /proc/meminfo | \
    awk '{print $2}'| paste -sd- - | bc
7513404
slm
źródło
@terdon - dzięki, że dokonałem tej edycji, kiedy to zrobiłeś 8-)
slm
3

Rozwiązanie całkowicie awk, bez zbędnych poleceń cat lub grep:

awk '/MemTotal/ {TOT=$2} /MemFree/ {FREE=$2} END {printf("%d kB Used\n", TOT-FREE)}' /proc/meminfo

Widzę, że awk_FTW mnie pobiło, ale pomyślałem, że formatowanie wyjścia może być przyjemne.

Johan
źródło
3

Spróbuj tego:

grep -P 'MemTotal|MemFree' /proc/meminfo | \
awk 'NR==1{s=$2;next}{s-=$2}END{print s}'
Cuonglm
źródło