Szukam polecenia, które zaakceptuje (jako dane wejściowe) wiele wierszy tekstu, z których każdy zawiera jedną liczbę całkowitą, i wyświetli sumę tych liczb całkowitych.
Jako trochę tła mam plik dziennika, który zawiera pomiary czasu. Poprzez grepping dla odpowiednich wierszy i trochę sed
przeformatowania mogę wymienić wszystkie czasy w tym pliku. Chciałbym obliczyć sumę. Mogę przesłać to wyjście pośrednie do dowolnego polecenia w celu dokonania ostatecznej sumy. Zawsze używałem expr
w przeszłości, ale chyba, że działa w trybie RPN, nie sądzę, że sobie z tym poradzi (i nawet wtedy byłoby to trudne).
Jak mogę uzyskać sumowanie liczb całkowitych?
Odpowiedzi:
Trochę awk powinien to zrobić?
Uwaga: niektóre wersje awk mają dziwne zachowania, jeśli zamierzasz dodać coś przekraczającego 2 ^ 31 (2147483647). Zobacz komentarze, aby uzyskać więcej informacji. Jedną z sugestii jest użycie
printf
zamiastprint
:źródło
ls $@ | xargs -i pdftk {} dump_data | grep NumberOfPages | awk '{s+=$2} END {print s}'
awk '{s+=$1} END {printf "%.0f", s}' mydatafile
zamiast tego.Wklej zazwyczaj łączy wiersze wielu plików, ale można go również użyć do konwersji pojedynczych wierszy pliku w jeden wiersz. Flaga separatora pozwala przekazać równanie typu x + x do bc.
Alternatywnie, gdy wykonujesz orurowanie ze standardowego wejścia,
źródło
paste
można użyć myślnika-
jako nazwy pliku - co pozwoli ci potokować liczby z wyjścia polecenia do standardowego wyjścia wklejania bez potrzeby uprzedniego utworzenia pliku:<commands> | paste -sd+ - | bc
-
. (Jest to przydatne, jeśli chcesz połączyć plik ze standardowym wejściem).Wersja jednoliniowa w Pythonie:
źródło
python -c"import sys; print(sum(map(int, sys.stdin)))"
find . -name '*.epub' -exec stat -c %s '{}' \; | python -c "import sys; nums = [int(n) for n in sys.stdin if int(n) < 10000000]; print(sum(nums)/len(nums))"
import sys; print(sum(int(''.join(c for c in l if c.isdigit())) for l in sys.stdin))
Złożyłbym duże OSTRZEŻENIE na powszechnie akceptowane rozwiązanie:
to dlatego, że w tej formie awk używa 32-bitowej reprezentacji liczb całkowitych ze znakiem: przepełni się dla sum przekraczających 2147483647 (tj. 2 ^ 31).
Bardziej ogólną odpowiedzią (dla sumowania liczb całkowitych) byłoby:
źródło
echo -e "2147483647 \n 100" |awk '{s+=$1}END{print s}'
pokazuje2147483747
echo 999999999999999999 | awk '{s+=$1} END {printf "%.0f\n", s}'
produkuje1000000000000000000
Zwykły bash:
źródło
num
zdefiniowany? Wierzę, że jest to jakoś związane z< numbers.txt
wyrażeniem, ale nie jest jasne, w jaki sposób.Zauważ, że liczby ujemne poprzedzone znakiem minus powinny zostać przetłumaczone
dc
, ponieważ używa do tego_
raczej-
prefiksu niż prefiksu. Na przykład przeztr '-' '_' | dc -f- -e '...'
.Edycja: Ponieważ ta odpowiedź uzyskała tyle głosów „za niejasnością”, oto szczegółowe wyjaśnienie:
Wyrażenie
[+z1<r]srz1<rp
wykonuje następujące czynności :Jako pseudo-kod:
Aby naprawdę zrozumieć prostotę i moc
dc
, oto działający skrypt Pythona, który implementuje niektóre polecenia zdc
i wykonuje wersję powyższego polecenia w języku Python:źródło
(echo "0"; sed 's/$/ +/' inp; echo 'pq')|dc
.dc -e '0 0 [+?z1<m]dsmxp'
. Dlatego nie zapisujemy wszystkich liczb na stosie przed przetwarzaniem, ale odczytujemy i przetwarzamy je jeden po drugim (a dokładniej, linia po linii, ponieważ jedna linia może zawierać kilka liczb). Zauważ, że pusty wiersz może zakończyć sekwencję wejściową.sed
podstawieniu można usunąć, ponieważdc
nie ma znaczenia spacje między argumentami a operatorami.(echo "0"; sed 's/$/+/' inputFile; echo 'pq')|dc
Z jq :
źródło
Czysty i krótki bash.
źródło
f=$(<numbers.txt)
.f=$(cat); echo $(( ${f//$'\n'/+} ))
skrypt, możesz potokować wszystko do tego skryptu lub wywoływać go bez argumentów na interaktywne wejście standardowego wejścia (zakończ za pomocą Control-D).<numbers.txt
Jest to ulepszenie, ale ogólnie rzecz biorąc, to rozwiązanie jest skuteczne tylko w przypadku małych plików wejściowych; na przykład przy pliku 1000 wierszy wejściowych zaakceptowaneawk
rozwiązanie jest około 20 razy szybsze na moim komputerze - a także zużywa mniej pamięci, ponieważ plik nie jest odczytywany jednocześnie.źródło
Moje piętnaście centów:
Przykład:
źródło
grep -v '^$'
. Dzięki!Zrobiłem szybki test porównawczy na istniejące odpowiedzi, które
lua
lubrocket
),Zawsze dodawałem liczby od 1 do 100 milionów, które były możliwe do wykonania na mojej maszynie w mniej niż minutę dla kilku rozwiązań.
Oto wyniki:
Pyton
Awk
Wklej i Bc
Na mojej maszynie zabrakło pamięci. To działało dla połowy wielkości wejściowej (50 milionów liczb):
Sądzę więc, że zajęłoby to około 35 sekund dla 100 milionów liczb.
Perl
Rubin
do
Dla porównania, skompilowałem wersję C i przetestowałem ją również, aby zorientować się, o ile wolniejsze są rozwiązania oparte na narzędziach.
Wniosek
C jest oczywiście najszybszy z 8s, ale rozwiązanie Pypy dodaje tylko niewielki narzut około 30% do 11s . Ale, szczerze mówiąc, Pypy nie jest dokładnie standardem. Większość ludzi ma zainstalowany tylko CPython, który jest znacznie wolniejszy (22 s), dokładnie tak szybko, jak popularne rozwiązanie Awk.
Najszybszym rozwiązaniem opartym na standardowych narzędziach jest Perl (15s).
źródło
paste
+bc
Podejście zostało tylko to, co szukałem do sumy wartości hex, dzięki!use std::io::{self, BufRead}; fn main() { let stdin = io::stdin(); let mut sum: i64 = 0; for line in stdin.lock().lines() { sum += line.unwrap().parse::<i64>().unwrap(); } println!("{}", sum); }
Prosta podszewka z jedną wkładką
źródło
echo $(( $( tr "\n" "+" < /tmp/test) 0 ))
tr
nie jest dokładnie „zwykłym uderzeniem” / nitpickRozwiązanie BASH, jeśli chcesz ustawić to jako polecenie (np. Jeśli musisz to robić często):
Następnie użycie:
źródło
Myślę, że AWK jest tym, czego szukasz:
Możesz użyć tego polecenia albo przez przekazanie listy liczb przez standardowe wejście, albo przez przekazanie pliku zawierającego liczby jako parametru.
źródło
Następujące działa w bash:
źródło
cat numbers.txt
krok byłby problematyczny.Możesz używać num-utils, chociaż może to być przesada w stosunku do tego, czego potrzebujesz. Jest to zestaw programów do manipulowania liczbami w powłoce i może robić kilka fajnych rzeczy, w tym oczywiście dodawać je. To trochę nieaktualne, ale nadal działają i mogą być przydatne, jeśli chcesz zrobić coś więcej.
http://suso.suso.org/programs/num-utils/
źródło
numsum numbers.txt
.Zdaję sobie sprawę, że to stare pytanie, ale podoba mi się to rozwiązanie, aby je udostępnić.
Jeśli jest zainteresowanie, wyjaśnię, jak to działa.
źródło
Pure Bash w jednej linijce :-)
źródło
((
nawiasy))
?$(< numbers.txt)
źródło
Alternatywny czysty Perl, dość czytelny, nie wymaga żadnych pakietów ani opcji:
źródło
Dla miłośników rubinów
źródło
Nie można uniknąć przesłania tego:
Można go znaleźć tutaj:
najbardziej elegancki jednowarstwowy płaszcz unixowy do sumowania liczb o dowolnej precyzji?
A oto jego szczególne zalety w stosunku do awk, bc i przyjaciół:
źródło
Korzystanie z GNU
datamash
util :Wynik:
Jeśli dane wejściowe są nieregularne, ze spacjami i tabulatorami w nieparzystych miejscach, może to mylić
datamash
, a następnie użyj-W
przełącznika:... lub użyj
tr
do wyczyszczenia białych znaków:źródło
Moja wersja:
źródło
seq -s+ -5 10 | bc
Możesz to zrobić w pythonie, jeśli czujesz się komfortowo:
Nie testowane, po prostu wpisane:
Sebastian wskazał jeden skrypt liniowy:
źródło
cat
służy do wykazania, że skrypt działa zarówno dla standardowego wejścia, jak i dla plików w argv [] (jakwhile(<>)
w Perlu). Jeśli dane wejściowe znajdują się w pliku, wówczas „<” nie jest konieczne.< numbers.txt
pokazuje, że działa tak samo dobrze, jak standardowecat numbers.txt |
. I nie uczy złych nawyków.Lub możesz wpisać liczby w wierszu poleceń:
Jednak ten plik sluruje plik, więc nie jest dobrym pomysłem stosowanie do dużych plików. Zobacz odpowiedź j_random_hackera, która pozwala uniknąć osiadania.
źródło
Poniższe powinno działać (zakładając, że Twój numer jest drugim polem w każdej linii).
źródło
One-liner in Racket:
źródło
C (nie uproszczony)
źródło
Z góry przepraszamy za czytelność tylnych kresek („'”), ale działają one w powłokach innych niż bash, a zatem są łatwiejsze do wklejenia. Jeśli używasz powłoki, która ją akceptuje, format $ (polecenie ...) jest znacznie bardziej czytelny (a przez to debugowalny) niż `polecenie ... ', więc możesz modyfikować dla własnego zdrowia psychicznego.
Mam prostą funkcję w moim bashrc, która użyje awk do obliczenia liczby prostych elementów matematycznych
To zrobi +, -, *, /, ^,%, sqrt, sin, cos, nawias ... (i więcej w zależności od twojej wersji awk) ... możesz nawet się spodobać z printf i formatem zmiennoprzecinkowym wyjście, ale to wszystko, czego zwykle potrzebuję
w przypadku tego konkretnego pytania po prostu zrobiłbym to dla każdej linii:
więc blok kodu sumujący każdą linię wyglądałby mniej więcej tak:
To jest, jeśli chcesz sumować je tylko linia po linii. Jednak w sumie dla każdej liczby w pliku danych
btw, jeśli muszę zrobić coś szybko na pulpicie, używam tego:
źródło
$()
?