Jak mogę sumować liczby na liniach w pliku

24

Mam plik, który wygląda następująco:

1
3
4
1
4
3
1
2

Jak mogę znaleźć sumę tego (tj. 1 + 3 + 4 + 1 + 4 + 3 + 1 + 2 = 19)?

Tim
źródło
1
Dla kontekstu liczę liczbę odznak, które mam na Ask Ubuntu z interfejsu API Stack Exchange.
Tim
Zcat badges.json | grep -o '"award_count":[0-9],"rank":"gold"' | grep -o [0-9]
Timem
Chociaż teraz zdaję sobie sprawę, że API ma badge_countmetodę.
Tim
Jeśli liczysz odznaki z interfejsu API, język, którego używasz do wysyłania zapytań do interfejsu API, nie może tego zrobić (python, javascript)?
Braiam

Odpowiedzi:

42

bcz niewielką pomocą, pasteaby uzyskać linie w jednym z +separatorem:

paste -sd+ file.txt | bc

Aby użyć wyniku grep(lub dowolnej innej komendy) zamiast pliku statycznego, przekaż grepSTDOUT do STDIN w paste:

grep .... | paste -sd+ | bc

Przykład:

% cat file.txt            
1
3
4
1
4
3
1
2

% paste -sd+ file.txt | bc
19

% grep . file.txt | paste -sd+ | bc
19

Jeśli musisz użyć bash, możesz użyć tablicy do zapisania zawartości pliku, a następnie iteracji po elementach lub możesz odczytać plik linia po linii i wykonać sumę dla każdej linii, drugie podejście byłoby bardziej wydajne:

$ time { nums=$(<file.txt); for i in ${nums[@]}; do (( sum+=i )); done; echo $sum ;}
19

real    0m0.002s
user    0m0.000s
sys 0m0.000s

$ time { while read i; do (( sum+=i )); done <file.txt; echo $sum ;}
19

real    0m0.000s
user    0m0.000s
sys 0m0.000s
heemayl
źródło
Hmmm nieźle. Przepraszam, że mogę zmienić pytanie: czy mogę to zmienić, aby zaakceptować wyjście grep (lub ustawić jedną linię jak cat file.txt | bc?
Tim
@ Tim Sprawdź moje zmiany
heemayl
Ta, to było proste!
Tim
2
standardowy sposób nie działał dla mnie, dopóki nie odkryłem w innej odpowiedzi, której musiałem użyć paste -sd+ -. Proszę to poprawić.
Xerus
19

Możesz także użyć awk. Aby policzyć całkowitą liczbę wierszy w plikach * .txt zawierających słowo „cześć”:

grep -ch 'hello' *.txt | awk '{n += $1}; END{print n}'

Aby po prostu zsumować liczby w pliku:

awk '{n += $1}; END{print n}' file.txt
CrazyApe84
źródło
Ale jeśli ten wiersz ma wartość „4”, nie będzie liczony 4, będzie. Będzie się liczyć 1.
Tim
Nie, to się liczy 4.
CrazyApe84,
Chcę sumę liczb w pliku. Czy to to robi?
Tim
Myślałem, że zmieniłeś swoje pytanie na wyjście grep. Robiłem pewne założenia. Dodam, jak po prostu zsumować wartości w pliku.
CrazyApe84,
2
Tak. To naprawdę ta sama odpowiedź co heemayl, ale zamiast wkleić i bc używa awk, co ostatecznie daje o wiele większą elastyczność. Mimo to jego odpowiedź jest dobra i był pierwszy, więc zasługuje na twój głos!
CrazyApe84,
7

Użyj numsumz paczki num-utils!

(Być może trzeba sudo apt-get install num-utils)

Komenda numsumdomyślnie wykonuje dokładnie to, czego potrzebujesz;

$ numsum file.txt 
19

Odczytywanie liczb testowych linia po linii z stdin:

$ printf '
1 
3
4
1
4
3
1
2' | numsum
19

Lub czytanie z jednej linii:

$ printf '1 3 4 1 4 3 1 2' | numsum -r
19


Więcej narzędzi

Pakiet zawiera inne narzędzia do przetwarzania liczb, które zasługują na większą popularność:

numaverage   - find the average of the numbers, or the mode or median
numbound     - find minimum of maximum of all lines
numgrep      - to find numbers matching ranges or sets
numinterval  - roughly like the first derivative
numnormalize - normalize numbers to an interval, like 0-1
numrandom    - random numbers from ranges or sets, eg odd.  
numrange     - similar to seq
numround     - round numbers up, down or to nearest

oraz bardziej ogólne polecenie kalkulatora numprocess,
które stosuje wyrażenie z wiersza poleceń do liczb w wierszach wprowadzania.

Volker Siegel
źródło
1

Możesz użyć awkrodzimej aplikacji linux przydatnej do skanowania i przetwarzania plików ze wzorem w linii. W przypadku twojego pytania wygeneruje to, co chcesz:

awk 'BEGIN { sum=0 } { sum+=$1 } END {print sum }' file.txt

Rury są również akceptowane:

cat file.txt | awk 'BEGIN { sum=0 } { sum+=$1 } END {print sum }'
gwarah
źródło
Nie ma potrzeby BEGIN{}blokowania, patrz odpowiedź CrazyApe84 .
terdon
Jest zbędny w stosunku do tego problemu, ale wolałem go uwzględnić ze względu na cel dydaktyczny.
gwarah
Ale czego to uczy? Jest redundantny dla każdego problemu, awknie jest C, nie trzeba ustawiać zmiennej przed użyciem. Spróbować awk 'BEGIN{print c+=1}'.
terdon
BEGIN {}blok nie został zaprojektowany tylko do inicjowania zmiennych. Bierze udział w specyfikacji projektu. W przypadku niektórych problemów może to być potrzebne.
gwarah
0

Jest to dość proste użycie bashskryptów.

SUM=0; for line in `cat file.txt`; do SUM=$((SUM + line)); done
zomfg_zombie
źródło
Jest to o wiele prostsze i minimalistyczny zestaw narzędzi niż obecne rozwiązanie.
Det
0

Rozwiązanie Perla:

$ perl -lnae '$c+=$_;END{print $c}' input.txt                                                                            
19

Powyższe może sumować wszystkie liczby w wielu plikach:

$ perl -lnae '$c+=$_;END{print $c}' input.txt input2.txt                                                                 
34

W przypadku wielu plików podanych w wierszu poleceń, w których chcemy zobaczyć sumę liczb w poszczególnych plikach, możemy to zrobić:

$ perl -lnae '$c+=$_;if(eof){printf("%d %s\n",$c,$ARGV);$c=0}' input.txt input2.txt                                      
19 input.txt
15 input2.txt
Sergiy Kolodyazhnyy
źródło
0

Prosty -

awk '{total+=$1} END{print total}' file

dodaje liczby i daje sumę.

Sufyan Ramzan
źródło
0

Prostym podejściem jest użycie wbudowanej funkcji powłoki:

SUM=0; while read N; do SUM=$((SUM+N)); done </path/to/file
echo $SUM

Spowoduje to odczytanie pliku linii, podsumowanie i wydrukowanie wyniku.

Jeśli chcesz użyć potoku i używać tylko pierwszego wiersza, działa to tak:

SUM=0
your_command | while read -r LINE; do for N in $LINE; do break; done; SUM=$((SUM+N)); done
echo $SUM

Uzyskanie pierwszego elementu odbywa się w następujący sposób:

LIST="foo bar baz"
for OBJ in $LIST; do break; done
echo $OBJ

foo
Bastian Bittorf
źródło