Shell-Befehl zum Summieren von ganzen Zahlen, eine pro Zeile?

867

Ich suche nach einem Befehl, der mehrere Textzeilen (als Eingabe) akzeptiert, wobei jede Zeile eine einzelne Ganzzahl enthält, und die Summe dieser Ganzzahlen ausgibt.

Als Hintergrund habe ich eine Protokolldatei, die Timing-Messungen enthält. Durch Suchen nach den relevanten Zeilen und ein wenig sedNeuformatieren kann ich alle Timings in dieser Datei auflisten . Ich würde gerne die Summe berechnen. Ich kann diese Zwischenausgabe an jeden Befehl weiterleiten, um die endgültige Summe zu erstellen. Ich habe es exprin der Vergangenheit immer verwendet , aber wenn es nicht im RPN-Modus läuft, denke ich nicht, dass es damit fertig wird (und selbst dann wäre es schwierig).

Wie kann ich die Summe der ganzen Zahlen erhalten?

Andrzej Doyle
quelle
2
Dies ist sehr ähnlich zu einer Frage, die ich vor einiger
An̲̳̳drew
5
Ich mag diese Frage wirklich, weil es viele mögliche richtige (oder zumindest funktionierende) Antworten gibt.
Francisco Canedo
Diese Frage scheint ein Problem für Code Golf zu sein. codegolf.stackexchange.com :)
Gordon Bean

Antworten:

1322

Ein bisschen awk sollte es tun?

awk '{s+=$1} END {print s}' mydatafile

Hinweis: Einige Versionen von awk weisen merkwürdige Verhaltensweisen auf, wenn Sie etwas hinzufügen, das 2 ^ 31 (2147483647) überschreitet. Weitere Hintergrundinformationen finden Sie in den Kommentaren. Ein Vorschlag ist, printfeher zu verwenden als print:

awk '{s+=$1} END {printf "%.0f", s}' mydatafile
Paul Dixon
quelle
7
Es gibt viel Liebe in diesem Raum! Mir gefällt, wie ein einfaches Skript wie dieses geändert werden kann, um eine zweite Datenspalte zu addieren, indem einfach $ 1 in $ 2 geändert wird
Paul Dixon
2
Es gibt keine praktische Grenze, da die Eingabe als Stream verarbeitet wird. Wenn es also eine Datei mit X Zeilen verarbeiten kann, können Sie ziemlich sicher sein, dass es X + 1 verarbeiten kann.
Paul Dixon
4
Ich habe einmal einen rudimentären Mailinglisten-Prozessor mit einem awk-Skript geschrieben, das über das Urlaubsdienstprogramm ausgeführt wird. Gute Zeiten. :)
LS
2
ls $@ | xargs -i pdftk {} dump_data | grep NumberOfPages | awk '{s+=$2} END {print s}'
Fliegende Schafe
8
Seien Sie vorsichtig, es funktioniert nicht mit Zahlen größer als 2147483647 (dh 2 ^ 31), da awk eine 32-Bit-Ganzzahldarstellung mit Vorzeichen verwendet. Verwenden Sie awk '{s+=$1} END {printf "%.0f", s}' mydatafilestattdessen.
Giancarlo Sportelli
665

Beim Einfügen werden normalerweise Zeilen mehrerer Dateien zusammengeführt. Es kann jedoch auch verwendet werden, um einzelne Zeilen einer Datei in eine einzelne Zeile zu konvertieren. Mit dem Begrenzer-Flag können Sie eine Gleichung vom Typ x + x an bc übergeben.

paste -s -d+ infile | bc

Alternativ, wenn Rohrleitungen von stdin,

<commands> | paste -s -d+ - | bc
Radoulov
quelle
1
Sehr schön! Ich hätte ein Leerzeichen vor das "+" gesetzt, um es besser analysieren zu können, aber das war sehr praktisch, um einige Speichernummern durch Einfügen und dann bc zu leiten.
Michael H.
73
Viel einfacher zu merken und zu tippen als die awk-Lösung. Beachten Sie auch, dass pasteein Strich -als Dateiname verwendet werden kann, mit dem Sie die Zahlen aus der Ausgabe eines Befehls in die Standardausgabe von Paste einfügen können, ohne zuerst eine Datei erstellen zu müssen:<commands> | paste -sd+ - | bc
George
19
Ich habe eine Datei mit 100 Millionen Nummern. Der Befehl awk dauert 21 Sekunden. Der Einfügebefehl dauert 41 Sekunden. Aber trotzdem gut 'Paste' zu treffen!
Abhi
4
@Abhi: Interessant: Ich schätze, ich würde 20s brauchen, um den awk-Befehl herauszufinden, damit er sich ausgleicht, bis ich 100 Millionen und eine Zahl versuche: D
Mark K Cowan
6
@ George Du kannst das aber weglassen -. (Es ist nützlich, wenn Sie eine Datei mit stdin kombinieren möchten).
Alois Mahdal
128

Die einzeilige Version in Python:

$ python -c "import sys; print(sum(int(l) for l in sys.stdin))"
dF.
quelle
Der obige Einzeiler funktioniert nicht für Dateien in sys.argv [], aber dieser funktioniert auf stackoverflow.com/questions/450799/…
jfs
Richtig - der Autor sagte, er würde die Ausgabe eines anderen Skripts in den Befehl leiten und ich habe versucht, es so kurz wie möglich zu machen :)
dF.
39
Kürzere Version wärepython -c"import sys; print(sum(map(int, sys.stdin)))"
jfs
4
Ich liebe diese Antwort wegen ihrer einfachen Lesbarkeit und Flexibilität. Ich brauchte die durchschnittliche Größe von Dateien kleiner als 10 MB in einer Sammlung von Verzeichnissen und änderte es zu diesem: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))"
Paul Whipp
1
Sie können auch Nicht-Zahlen herausfiltern, wenn Sie Text eingemischt haben:import sys; print(sum(int(''.join(c for c in l if c.isdigit())) for l in sys.stdin))
Granitosaurus
91

Ich würde eine große WARNUNG auf die allgemein genehmigte Lösung setzen:

awk '{s+=$1} END {print s}' mydatafile # DO NOT USE THIS!!

Dies liegt daran, dass awk in dieser Form eine vorzeichenbehaftete 32-Bit-Ganzzahldarstellung verwendet: Sie läuft für Summen über, die 2147483647 (dh 2 ^ 31) überschreiten.

Eine allgemeinere Antwort (zum Summieren von ganzen Zahlen) wäre:

awk '{s+=$1} END {printf "%.0f\n", s}' mydatafile # USE THIS INSTEAD
Giancarlo Sportelli
quelle
Warum hilft printf () hier? Der Überlauf des int ist zuvor aufgetreten, da der Summierungscode derselbe ist.
Robert Klemme
9
Weil das Problem tatsächlich in der "Druck" -Funktion liegt. Awk verwendet 64-Bit-Ganzzahlen, aber aus irgendeinem Grund skaliert print sie nicht auf 32-Bit.
Giancarlo Sportelli
4
Der Druckfehler scheint behoben zu sein, zumindest für awk 4.0.1 & bash 4.3.11, es sei denn, ich irre mich: echo -e "2147483647 \n 100" |awk '{s+=$1}END{print s}'Shows2147483747
Xen2050
4
Die Verwendung von Floats führt nur zu einem neuen Problem: echo 999999999999999999 | awk '{s+=$1} END {printf "%.0f\n", s}'Produziert1000000000000000000
Patrick
1
Sollte die Verwendung von "% ld" auf 64-Bit-Systemen nicht funktionieren, damit printf nicht auf 32-Bit abgeschnitten wird? Wie @Patrick betont, sind Floats hier keine gute Idee.
Yerforkferchips
78

Plain Bash:

$ cat numbers.txt 
1
2
3
4
5
6
7
8
9
10
$ sum=0; while read num; do ((sum += num)); done < numbers.txt; echo $sum
55
Giacomo
quelle
2
Ein kleinerer Liner: stackoverflow.com/questions/450799/…
Khaja Minhajuddin
@ Jack, wo ist numdefiniert? Ich glaube irgendwie, dass es mit dem < numbers.txtAusdruck zusammenhängt, aber es ist nicht klar, wie.
Atcold
66
dc -f infile -e '[+z1<r]srz1<rp'

Beachten Sie, dass negative Zahlen mit Minuszeichen übersetzt werden sollten dc, da hierfür _eher ein -Präfix als ein Präfix verwendet wird. Zum Beispiel über tr '-' '_' | dc -f- -e '...'.

Bearbeiten: Da diese Antwort so viele Stimmen "für Dunkelheit" erhielt, ist hier eine detaillierte Erklärung:

Der Ausdruck [+z1<r]srz1<rp bewirkt Folgendes :

[   interpret everything to the next ] as a string
  +   push two values off the stack, add them and push the result
  z   push the current stack depth
  1   push one
  <r  pop two values and execute register r if the original top-of-stack (1)
      is smaller
]   end of the string, will push the whole thing to the stack
sr  pop a value (the string above) and store it in register r
z   push the current stack depth again
1   push 1
<r  pop two values and execute register r if the original top-of-stack (1)
    is smaller
p   print the current top-of-stack

Als Pseudocode:

  1. Definieren Sie "add_top_of_stack" als:
    1. Entfernen Sie die beiden oberen Werte vom Stapel und fügen Sie das Ergebnis wieder hinzu
    2. Wenn der Stapel zwei oder mehr Werte hat, führen Sie "add_top_of_stack" rekursiv aus
  2. Wenn der Stapel zwei oder mehr Werte hat, führen Sie "add_top_of_stack" aus.
  3. Drucken Sie das Ergebnis aus, jetzt das einzige Element im Stapel

Um die Einfachheit und Leistungsfähigkeit von wirklich zu verstehen dc, finden Sie hier ein funktionierendes Python-Skript, das einige der Befehle aus dceiner Python-Version des obigen Befehls implementiert und ausführt:

### Implement some commands from dc
registers = {'r': None}
stack = []
def add():
    stack.append(stack.pop() + stack.pop())
def z():
    stack.append(len(stack))
def less(reg):
    if stack.pop() < stack.pop():
        registers[reg]()
def store(reg):
    registers[reg] = stack.pop()
def p():
    print stack[-1]

### Python version of the dc command above

# The equivalent to -f: read a file and push every line to the stack
import fileinput
for line in fileinput.input():
    stack.append(int(line.strip()))

def cmd():
    add()
    z()
    stack.append(1)
    less('r')

stack.append(cmd)
store('r')
z()
stack.append(1)
less('r')
p()
André Laszlo
quelle
2
Gleichstrom ist nur das Werkzeug der Wahl. Aber ich würde es mit etwas weniger Stack-Ops machen. Angenommen, alle Zeilen enthalten wirklich eine Zahl : (echo "0"; sed 's/$/ +/' inp; echo 'pq')|dc.
Ikrabbe
5
Der Online-Algorithmus : dc -e '0 0 [+?z1<m]dsmxp'. Wir speichern also nicht alle Zahlen vor der Verarbeitung auf dem Stapel, sondern lesen und verarbeiten sie einzeln (genauer gesagt, Zeile für Zeile, da eine Zeile mehrere Zahlen enthalten kann). Beachten Sie, dass eine leere Zeile eine Eingabesequenz beenden kann.
Ruvim
@ikrabbe das ist toll. Es kann tatsächlich um ein weiteres Zeichen gekürzt werden: Das Leerzeichen in der sedErsetzung kann entfernt werden, da dc Leerzeichen zwischen Argumenten und Operatoren nicht berücksichtigt werden. (echo "0"; sed 's/$/+/' inputFile; echo 'pq')|dc
WhiteHotLoveTiger
58

Mit jq :

seq 10 | jq -s 'add' # 'add' is equivalent to 'reduce .[] as $item (0; . + $item)'
Banyan
quelle
7
Ich mag das, weil ich denke, es ist so klar und kurz, dass ich mich vielleicht tatsächlich daran erinnern kann.
Alfe
46

Reine und kurze Bash.

f=$(cat numbers.txt)
echo $(( ${f//$'\n'/+} ))
Daniel
quelle
9
Dies ist die beste Lösung, da kein Unterprozess erstellt wird, wenn Sie die erste Zeile durch ersetzen f=$(<numbers.txt).
Loentar
1
Wie kann man die Eingabe von stdin haben? wie aus einer Pfeife?
NJZK2
@ njzk2 Wenn Sie f=$(cat); echo $(( ${f//$'\n'/+} ))ein Skript einfügen , können Sie alles an dieses Skript weiterleiten oder es ohne Argumente für die interaktive stdin-Eingabe aufrufen (mit Control-D beenden).
mklement0
5
@loentar Das <numbers.txtist eine Verbesserung, aber insgesamt ist diese Lösung nur für kleine Eingabedateien effizient. Bei einer Datei mit 1.000 Eingabezeilen ist die akzeptierte awkLösung auf meinem Computer beispielsweise etwa 20-mal schneller - und verbraucht außerdem weniger Speicher, da die Datei nicht alle auf einmal gelesen wird.
mklement0
2
Ich hatte fast die Hoffnung verloren, als ich diese erreichte. Pure Bash!
Omer Akhter
37
perl -lne '$x += $_; END { print $x; }' < infile.txt
j_random_hacker
quelle
4
Und ich habe sie wieder hinzugefügt: "-l" stellt sicher, dass die Ausgabe als Shell-`` Backticks LF-terminiert wird und die meisten Programme dies erwarten, und "<" gibt an, dass dieser Befehl in einer Pipeline verwendet werden kann.
j_random_hacker
Du hast recht. Als Entschuldigung: Jeder Charakter in Perl-Einzeilern erfordert eine mentale Arbeit für mich, deshalb ziehe ich es vor, so viele Charaktere wie möglich zu entfernen. Die Gewohnheit war in diesem Fall schädlich.
JFS
2
Eine der wenigen Lösungen, die nicht alles in den Arbeitsspeicher laden.
Erik Aronesty
28

Meine fünfzehn Cent:

$ cat file.txt | xargs  | sed -e 's/\ /+/g' | bc

Beispiel:

$ cat text
1
2
3
3
4
5
6
78
9
0
1
2
3
4
576
7
4444
$ cat text | xargs  | sed -e 's/\ /+/g' | bc 
5148
unschuldige Welt
quelle
Meine Eingabe könnte Leerzeilen enthalten, daher habe ich das verwendet, was Sie hier gepostet haben, plus a grep -v '^$'. Vielen Dank!
James Oravec
Beeindruckend!! Ihre Antwort ist unglaublich! Mein persönlicher Favorit von allen im Profil
Thahgr
Ich liebe das und +1 für die Pipeline. Sehr einfache und leichte Lösung für mich
Gelin Luo
24

Ich habe einen kurzen Benchmark für die vorhandenen Antworten durchgeführt, die

  • benutze nur Standardwerkzeuge (sorry für Sachen wie luaoder rocket),
  • sind echte Einzeiler,
  • sind in der Lage, große Mengen von Zahlen (100 Millionen) hinzuzufügen, und
  • sind schnell (ich habe diejenigen ignoriert, die länger als eine Minute gedauert haben).

Ich habe immer die Zahlen 1 bis 100 Millionen hinzugefügt, die für mehrere Lösungen in weniger als einer Minute auf meinem Computer ausgeführt werden konnten.

Hier sind die Ergebnisse:

Python

:; seq 100000000 | python -c 'import sys; print sum(map(int, sys.stdin))'
5000000050000000
# 30s
:; seq 100000000 | python -c 'import sys; print sum(int(s) for s in sys.stdin)'
5000000050000000
# 38s
:; seq 100000000 | python3 -c 'import sys; print(sum(int(s) for s in sys.stdin))'
5000000050000000
# 27s
:; seq 100000000 | python3 -c 'import sys; print(sum(map(int, sys.stdin)))'
5000000050000000
# 22s
:; seq 100000000 | pypy -c 'import sys; print(sum(map(int, sys.stdin)))'
5000000050000000
# 11s
:; seq 100000000 | pypy -c 'import sys; print(sum(int(s) for s in sys.stdin))'
5000000050000000
# 11s

Awk

:; seq 100000000 | awk '{s+=$1} END {print s}'
5000000050000000
# 22s

Paste & Bc

Auf meinem Computer ging der Speicher aus. Es funktionierte für die Hälfte der Größe der Eingabe (50 Millionen Zahlen):

:; seq 50000000 | paste -s -d+ - | bc
1250000025000000
# 17s
:; seq 50000001 100000000 | paste -s -d+ - | bc
3750000025000000
# 18s

Ich denke, es hätte ~ 35 Sekunden für die 100 Millionen Zahlen gedauert.

Perl

:; seq 100000000 | perl -lne '$x += $_; END { print $x; }'
5000000050000000
# 15s
:; seq 100000000 | perl -e 'map {$x += $_} <> and print $x'
5000000050000000
# 48s

Rubin

:; seq 100000000 | ruby -e "puts ARGF.map(&:to_i).inject(&:+)"
5000000050000000
# 30s

C.

Nur zum Vergleich habe ich die C-Version kompiliert und auch getestet, um eine Vorstellung davon zu bekommen, wie viel langsamer die werkzeugbasierten Lösungen sind.

#include <stdio.h>
int main(int argc, char** argv) {
    long sum = 0;
    long i = 0;
    while(scanf("%ld", &i) == 1) {
        sum = sum + i;
    }
    printf("%ld\n", sum);
    return 0;
}

 

:; seq 100000000 | ./a.out 
5000000050000000
# 8s

Fazit

C ist mit 8s natürlich am schnellsten, aber die Pypy-Lösung fügt 11s nur einen sehr geringen Overhead von etwa 30% hinzu . Aber um fair zu sein, ist Pypy nicht gerade Standard. Die meisten Leute haben nur CPython installiert, das deutlich langsamer ist (22s), genau so schnell wie die beliebte Awk-Lösung.

Die schnellste Lösung, die auf Standardwerkzeugen basiert, ist Perl (15s).

Alfe
quelle
2
Der paste+ bcAnsatz war genau das, wonach ich gesucht habe, um Hex-Werte zu summieren, danke!
Tomislav Nakic-Alfirevic
1
Nur zum Spaß, in Rust: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); }
Jocelyn
tolle Antwort. Nicht zu picken, aber es ist der Fall, dass die Antwort noch
Steven Lu
@StevenLu Ich hatte das Gefühl, die Antwort wäre nur länger und damit weniger großartig (um deine Worte zu verwenden). Aber ich kann verstehen, dass dieses Gefühl nicht von allen geteilt werden muss :)
Alfe
Weiter: numba + parallelisation
gerrit
17

Einfach einen Liner schlagen

$ cat > /tmp/test
1 
2 
3 
4 
5
^D

$ echo $(( $(cat /tmp/test | tr "\n" "+" ) 0 ))
Khaja Minhajuddin
quelle
7
Keine Katze benötigt: echo $(( $( tr "\n" "+" < /tmp/test) 0 ))
Agc
2
trist nicht gerade "plain Bash" / nitpick
Benjamin W.
17

BASH-Lösung, wenn Sie dies zu einem Befehl machen möchten (z. B. wenn Sie dies häufig tun müssen):

addnums () {
  local total=0
  while read val; do
    (( total += val ))
  done
  echo $total
}

Dann Verwendung:

addnums < /tmp/nums
Jay
quelle
14

Ich denke, AWK ist das, wonach Sie suchen:

awk '{sum+=$1}END{print sum}'

Sie können diesen Befehl verwenden, indem Sie entweder die Zahlenliste über die Standardeingabe oder die Datei mit den Zahlen als Parameter übergeben.

Paolo
quelle
11

Folgendes funktioniert in bash:

I=0

for N in `cat numbers.txt`
do
    I=`expr $I + $N`
done

echo $I
Francisco Canedo
quelle
1
Die Befehlserweiterung sollte mit Vorsicht verwendet werden, wenn Dateien beliebig groß sein können. Bei numbers.txt von 10 MB wäre der cat numbers.txtSchritt problematisch.
Giacomo
1
In der Tat würde ich diese verwenden (wenn nicht für die hier gefundenen besseren Lösungen), bis ich tatsächlich auf dieses Problem gestoßen bin.
Francisco Canedo
11

Sie können num-utils verwenden, obwohl es für das, was Sie brauchen, möglicherweise übertrieben ist. Dies ist eine Reihe von Programmen zum Bearbeiten von Zahlen in der Shell, die mehrere raffinierte Aufgaben ausführen können, einschließlich natürlich der Addition. Es ist etwas veraltet, aber sie funktionieren immer noch und können nützlich sein, wenn Sie etwas mehr tun müssen.

http://suso.suso.org/programs/num-utils/

Sykora
quelle
Beispiel : numsum numbers.txt.
Agc
9

Mir ist klar, dass dies eine alte Frage ist, aber ich mag diese Lösung genug, um sie zu teilen.

% cat > numbers.txt
1 
2 
3 
4 
5
^D
% cat numbers.txt | perl -lpe '$c+=$_}{$_=$c'
15

Bei Interesse erkläre ich, wie es funktioniert.

Nym
quelle
10
Bitte nicht. Wir tun gerne so, als wären -n und -p nette semantische Dinge, nicht nur ein kluges Einfügen von Strings;)
hobbs
2
Ja bitte, erkläre es :) (Ich bin kein Perl-Typ.)
Jens
1
Versuchen Sie, "perl -MO = Deparse -lpe '$ c + = $ _} {$ _ = $ c'" auszuführen, und betrachten Sie die Ausgabe. Grundsätzlich verwendet -l Zeilenumbrüche und sowohl Eingabe- als auch Ausgabetrennzeichen, und -p druckt jede Zeile. Aber um '-p' zu machen, fügt Perl zuerst eine Kesselplatte hinzu (die -MO = Deparse) zeigt, aber dann ersetzt und kompiliert sie nur. Sie können also einen zusätzlichen Block mit dem Teil '} {' einfügen und ihn dazu verleiten, nicht in jeder Zeile zu drucken, sondern ganz am Ende zu drucken.
Nym
9

Pure Bash und in einem Einzeiler :-)

$ cat numbers.txt
1
2
3
4
5
6
7
8
9
10


$ I=0; for N in $(cat numbers.txt); do I=$(($I + $N)); done; echo $I
55
Oliver Ertl
quelle
Warum gibt es zwei ((Klammern ))?
Atcold
Nicht wirklich reine Bash wegen Katze. Machen Sie es zu einem reinen Schlag, indem Sie die Katze durch$(< numbers.txt)
Dani_l ersetzen.
9
sed 's/^/.+/' infile | bc | tail -1
Dominique
quelle
6

Alternative reine Perl, ziemlich lesbar, keine Pakete oder Optionen erforderlich:

perl -e "map {$x += $_} <> and print $x" < infile.txt
Clint
quelle
oder ein kleines bisschen kürzer: perl -e 'map {$ x + = $ _} <>; print $ x 'infile.txt
Avi Tevet
Der benötigte Speicher beträgt fast 2 GB für eine große Eingabe von 10 Millionen Zahlen
Amit Naidu
6

Für Rubinliebhaber

ruby -e "puts ARGF.map(&:to_i).inject(&:+)" numbers.txt
johnlinvc
quelle
5

Ich kann es nicht vermeiden, dies einzureichen:

jot 1000000 | sed '2,$s/$/+/;$s/$/p/' | dc

Es ist hier zu finden:
Der eleganteste Einzeiler der Unix-Shell, um die Liste der Zahlen mit beliebiger Genauigkeit zusammenzufassen?

Und hier sind seine besonderen Vorteile gegenüber awk, bc und Freunden:

  • es hängt nicht von der Pufferung ab und drosselt daher nicht mit wirklich großen Eingaben
  • Dies impliziert keine besondere Genauigkeit - oder Ganzzahlgröße -
  • Kein anderer Code erforderlich, wenn Gleitkommazahlen hinzugefügt werden müssen
fgeorgatos
quelle
Bitte geben Sie den Code für die Frage in der Antwort an und verweisen Sie nicht auf einen Link
Ibo
5

Verwenden des GNU datamash util :

seq 10 | datamash sum 1

Ausgabe:

55

Wenn die Eingabedaten unregelmäßig sind und Leerzeichen und Tabulatoren an ungeraden Stellen stehen, kann dies verwirrend datamashsein. Verwenden Sie dann entweder den -WSchalter:

<commands...> | datamash -W sum 1

... oder verwenden Sie tr, um das Leerzeichen zu bereinigen:

<commands...> | tr -d '[[:blank:]]' | datamash sum 1
agc
quelle
4

Meine Version:

seq -5 10 | xargs printf "- - %s" | xargs  | bc
Vytenis Bivainis
quelle
2
Kürzere:seq -s+ -5 10 | bc
Agc
3

Sie können es in Python tun, wenn Sie sich wohl fühlen:

Nicht getestet, nur getippt:

out = open("filename").read();
lines = out.split('\n')
ints = map(int, lines)
s = sum(ints)
print s

Sebastian wies auf ein Einzeilenskript hin:

cat filename | python -c"from fileinput import input; print sum(map(int, input()))"
Tiago
quelle
python -c "von Dateieingabe importieren Eingabe; Drucksumme (map (int, input ()))" numbers.txt
jfs
2
Katze ist überbeansprucht, leiten Sie stdin aus der Datei um: python -c "..." <numbers.txt
Giacomo
2
@rjack: catwird verwendet, um zu demonstrieren, dass das Skript sowohl für stdin als auch für Dateien in argv [] funktioniert (wie while(<>)in Perl). Wenn sich Ihre Eingabe in einer Datei befindet, ist '<' nicht erforderlich.
JFS
2
Aber < numbers.txtzeigt, dass es auf stdin genauso gut cat numbers.txt |funktioniert wie. Und es lehrt keine schlechten Gewohnheiten.
Xiong Chiamiov
3
$ cat n
2
4
2
7
8
9
$ perl -MList::Util -le 'print List::Util::sum(<>)' < n
32

Oder Sie können die Zahlen in der Befehlszeile eingeben:

$ perl -MList::Util -le 'print List::Util::sum(<>)'
1
3
5
^D
9

Dieser schlürft jedoch die Datei, so dass es keine gute Idee ist, sie für große Dateien zu verwenden. Siehe die Antwort von j_random_hacker, die ein Schlürfen vermeidet.

Sinan Ünür
quelle
3

Folgendes sollte funktionieren (vorausgesetzt, Ihre Nummer ist das zweite Feld in jeder Zeile).

awk 'BEGIN {sum=0} \
 {sum=sum + $2} \
END {print "tot:", sum}' Yourinputfile.txt
James Anderson
quelle
2
Sie brauchen den Teil {sum = 0} nicht wirklich
Uphill_ What '1
3

Einzeiler im Schläger:

racket -e '(define (g) (define i (read)) (if (eof-object? i) empty (cons i (g)))) (foldr + 0 (g))' < numlist.txt
b2coutts
quelle
3

C (nicht vereinfacht)

seq 1 10 | tcc -run <(cat << EOF
#include <stdio.h>
int main(int argc, char** argv) {
    int sum = 0;
    int i = 0;
    while(scanf("%d", &i) == 1) {
        sum = sum + i;
    }
    printf("%d\n", sum);
    return 0;
}
EOF)
Greg Bowyer
quelle
Ich musste den Kommentar positiv bewerten. An der Antwort ist nichts auszusetzen - sie ist ziemlich gut. Um jedoch zu zeigen, dass der Kommentar die Antwort großartig macht, stimme ich dem Kommentar nur zu.
bballdave025
3

Entschuldigung im Voraus für die Lesbarkeit der Backticks ("` "), aber diese funktionieren in anderen Shells als Bash und sind daher besser zu verarbeiten. Wenn Sie eine Shell verwenden, die dies akzeptiert, ist das Format $ (Befehl ...) viel besser lesbar (und damit debuggbar) als "Befehl ...". Sie können es also aus Gründen der Vernunft ändern.

Ich habe eine einfache Funktion in meinem Bashrc, die awk verwendet, um eine Reihe einfacher mathematischer Elemente zu berechnen

calc(){
  awk 'BEGIN{print '"$@"' }'
}

Dies führt zu +, -, *, /, ^,%, sqrt, sin, cos, Klammern ... (und mehr, abhängig von Ihrer Version von awk) ... Sie könnten sogar Lust auf printf und Format-Gleitkomma haben Ausgabe, aber das ist alles, was ich normalerweise brauche

Für diese spezielle Frage würde ich dies einfach für jede Zeile tun:

calc `echo "$@"|tr " " "+"`

Der Codeblock zum Summieren jeder Zeile würde also ungefähr so ​​aussehen:

while read LINE || [ "$LINE" ]; do
  calc `echo "$LINE"|tr " " "+"` #you may want to filter out some lines with a case statement here
done

Das ist, wenn Sie sie nur Zeile für Zeile summieren wollten. Jedoch für insgesamt jede Nummer in der Datendatei

VARS=`<datafile`
calc `echo ${VARS// /+}`

Übrigens, wenn ich etwas schnell auf dem Desktop tun muss, benutze ich Folgendes:

xcalc() { 
  A=`calc "$@"`
  A=`Xdialog --stdout --inputbox "Simple calculator" 0 0 $A`
  [ $A ] && xcalc $A
}
Technosaurus
quelle
2
Welche Art von alter Muschel verwenden Sie, die nicht unterstützt wird $()?
Nyuszika7h