Każdy wiersz zawiera tekst i liczby w jednej kolumnie. Muszę obliczyć sumę liczb w każdym rzędzie. Jak mogę to zrobić? Dzięki
example.log zawiera:
time=31sec
time=192sec
time=18sec
time=543sec
Odpowiedź powinna wynosić 784
Każdy wiersz zawiera tekst i liczby w jednej kolumnie. Muszę obliczyć sumę liczb w każdym rzędzie. Jak mogę to zrobić? Dzięki
example.log zawiera:
time=31sec
time=192sec
time=18sec
time=543sec
Odpowiedź powinna wynosić 784
Odpowiedzi:
W nowszej wersji (4.x) GNU awk
:
awk 'BEGIN {FPAT="[0-9]+"}{s+=$1}END{print s}'
Z innymi awk
s spróbuj:
awk -F '[a-z=]*' '{s+=$2}END{print s}'
s+0
w przypadku, gdy s
jest pusty, wydrukuje 0
zamiast pustego.
s
może być pusty; jeśli dane wejściowe nie zawierają wierszy (tj. jeśli w ogóle nie ma danych wejściowych ). W takim przypadku możliwe są dwa zachowania; 1) brak danych wejściowych => brak danych wyjściowych lub 2) zawsze coś wyjściowego, jeśli tylko 0. Oba są sensownymi opcjami w zależności od kontekstu aplikacji. Jest +0
to opcja adresowania 2). Aby rozwiązać opcję 1), wolisz pisać END {if(s) print s}
. - Dlatego nie ma sensu zakładać żadnej z opcji (w tym przypadku narożnym braku danych), dopóki nie zostanie to określone w pytaniu.
awk -F= '{sum+=$2};END{print sum}'
time=1.4e5sec
Kolejny GNU awk
:
awk -v RS='[0-9]+' '{n+=RT};END{print n}'
perl
Jeden:
perl -lne'$n+=$_ for/\d+/g}{print$n'
POSIX jeden:
tr -cs 0-9 '[\n*]' | grep . | paste -sd + - | bc
sed 's/=/ /' file | awk '{ sum+=$2 } END { print sum}'
sed
:awk --field-separator = '{ sum+=$2 } END { print sum}' data.dat
-F'='
zamiast--field-separator =
man awk
jedyny daje -F fs
i--field-separator fs
-F'='
lub -F '='
są na 2 sposoby -F fs
(w twoim przypadku fs to „=”). Dodałem pojedyncze cytaty, aby upewnić się, że fs jest poprawnie widziane i interpretowane przez awk, a nie powłokę (przydatne, jeśli fs to ';' na przykład)
Wszyscy opublikowali niesamowite awk
odpowiedzi, które bardzo mi się podobają.
Odmiana do @cuonglm wymianie grep
z sed
:
sed 's/[^0-9]//g' example.log | paste -sd'+' - | bc
sed
Paski wszystko z wyjątkiem numerów.paste -sd+ -
Komenda łączy wszystkie linie razem w jednej liniibc
Oblicza wyrażeniePowinieneś użyć kalkulatora.
{ tr = \ | xargs printf '[%s=]P%d+p' | dc; } <infile 2>/dev/null
Z czterema drukowanymi liniami:
time=31
time=223
time=241
time=784
I prościej:
tr times=c ' + p' <infile |dc
... które drukuje ...
31
223
241
784
Jeśli szukasz prędkości, to właśnie dc
tego chcesz. Tradycyjnie był bc
to kompilator - i wciąż jest dostępny dla wielu systemów.
dc
tak blisko, jak mogę powiedzieć. O czym mówisz?
perl
ze standardowym zestawem narzędzi unix - naprawdę nie ma sensu, jeśli używasz narzędzi GNU skompilowanych w łańcuchu narzędzi GNU. Wszystkie wzdęcia, które mogą negatywnie wpłynąć na wydajność Perla, występują również we wszystkich narzędziach GNU skompilowanych przez GNU. Smutne ale prawdziwe. Potrzebujesz prawdziwego, prosto zbudowanego, prostego zestawu narzędzi, aby dokładnie ocenić różnicę. Jak na przykład zestaw narzędzi rodowych, statycznie powiązany z bibliotekami muzułmańskimi - w ten sposób możesz porównać paradygmat jedno narzędzie / jedno zadanie z jednym narzędziem, aby rządzić nimi wszystkimi.
Poprzez python3,
import re
with open(file) as f:
m = f.read()
l = re.findall(r'\d+', m)
print(sum(map(int, l)))
re.findall
zwraca listę ciągów, to nie zadziała
sum(int(e) for e in l)
jest bardziej pythonowy.
Rozwiązanie Pure Bash (Bash 3+):
while IFS= read -r line; do # While it reads a line:
if [[ "$line" =~ [0-9]+ ]]; then # If the line contains numbers:
((counter+=BASH_REMATCH[0])) # Add the current number to counter
fi # End if.
done # End loop.
echo "Total number: $counter" # Print the number.
unset counter # Reset counter to 0.
Krótka wersja:
while IFS= read -r l; do [[ "$l" =~ [0-9]+ ]] && ((c+=BASH_REMATCH)); done; echo $c; c=0
PS4='$((x+=${time%s*}))' time=0 x=0 sh -x <infile