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 sed
Neuformatieren 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 expr
in 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?
Antworten:
Ein bisschen awk sollte es tun?
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,
printf
eher zu verwenden alsprint
:quelle
ls $@ | xargs -i pdftk {} dump_data | grep NumberOfPages | awk '{s+=$2} END {print s}'
awk '{s+=$1} END {printf "%.0f", s}' mydatafile
stattdessen.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.
Alternativ, wenn Rohrleitungen von stdin,
quelle
paste
ein 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
-
. (Es ist nützlich, wenn Sie eine Datei mit stdin kombinieren möchten).Die einzeilige Version in Python:
quelle
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))
Ich würde eine große WARNUNG auf die allgemein genehmigte Lösung setzen:
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:
quelle
echo -e "2147483647 \n 100" |awk '{s+=$1}END{print s}'
Shows2147483747
echo 999999999999999999 | awk '{s+=$1} END {printf "%.0f\n", s}'
Produziert1000000000000000000
Plain Bash:
quelle
num
definiert? Ich glaube irgendwie, dass es mit dem< numbers.txt
Ausdruck zusammenhängt, aber es ist nicht klar, wie.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 übertr '-' '_' | 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 :Als Pseudocode:
Um die Einfachheit und Leistungsfähigkeit von wirklich zu verstehen
dc
, finden Sie hier ein funktionierendes Python-Skript, das einige der Befehle ausdc
einer Python-Version des obigen Befehls implementiert und ausführt:quelle
(echo "0"; sed 's/$/ +/' inp; echo 'pq')|dc
.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.sed
Ersetzung kann entfernt werden, dadc
Leerzeichen zwischen Argumenten und Operatoren nicht berücksichtigt werden.(echo "0"; sed 's/$/+/' inputFile; echo 'pq')|dc
Mit jq :
quelle
Reine und kurze Bash.
quelle
f=$(<numbers.txt)
.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).<numbers.txt
ist eine Verbesserung, aber insgesamt ist diese Lösung nur für kleine Eingabedateien effizient. Bei einer Datei mit 1.000 Eingabezeilen ist die akzeptierteawk
Lösung auf meinem Computer beispielsweise etwa 20-mal schneller - und verbraucht außerdem weniger Speicher, da die Datei nicht alle auf einmal gelesen wird.quelle
Meine fünfzehn Cent:
Beispiel:
quelle
grep -v '^$'
. Vielen Dank!Ich habe einen kurzen Benchmark für die vorhandenen Antworten durchgeführt, die
lua
oderrocket
),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
Awk
Paste & Bc
Auf meinem Computer ging der Speicher aus. Es funktionierte für die Hälfte der Größe der Eingabe (50 Millionen Zahlen):
Ich denke, es hätte ~ 35 Sekunden für die 100 Millionen Zahlen gedauert.
Perl
Rubin
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.
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).
quelle
paste
+bc
Ansatz war genau das, wonach ich gesucht habe, um Hex-Werte zu summieren, danke!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); }
Einfach einen Liner schlagen
quelle
echo $(( $( tr "\n" "+" < /tmp/test) 0 ))
tr
ist nicht gerade "plain Bash" / nitpickBASH-Lösung, wenn Sie dies zu einem Befehl machen möchten (z. B. wenn Sie dies häufig tun müssen):
Dann Verwendung:
quelle
Ich denke, AWK ist das, wonach Sie suchen:
Sie können diesen Befehl verwenden, indem Sie entweder die Zahlenliste über die Standardeingabe oder die Datei mit den Zahlen als Parameter übergeben.
quelle
Folgendes funktioniert in bash:
quelle
cat numbers.txt
Schritt problematisch.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/
quelle
numsum numbers.txt
.Mir ist klar, dass dies eine alte Frage ist, aber ich mag diese Lösung genug, um sie zu teilen.
Bei Interesse erkläre ich, wie es funktioniert.
quelle
Pure Bash und in einem Einzeiler :-)
quelle
((
Klammern))
?$(< numbers.txt)
quelle
Alternative reine Perl, ziemlich lesbar, keine Pakete oder Optionen erforderlich:
quelle
Für Rubinliebhaber
quelle
Ich kann es nicht vermeiden, dies einzureichen:
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:
quelle
Verwenden des GNU
datamash
util :Ausgabe:
Wenn die Eingabedaten unregelmäßig sind und Leerzeichen und Tabulatoren an ungeraden Stellen stehen, kann dies verwirrend
datamash
sein. Verwenden Sie dann entweder den-W
Schalter:... oder verwenden Sie
tr
, um das Leerzeichen zu bereinigen:quelle
Meine Version:
quelle
seq -s+ -5 10 | bc
Sie können es in Python tun, wenn Sie sich wohl fühlen:
Nicht getestet, nur getippt:
Sebastian wies auf ein Einzeilenskript hin:
quelle
cat
wird verwendet, um zu demonstrieren, dass das Skript sowohl für stdin als auch für Dateien in argv [] funktioniert (wiewhile(<>)
in Perl). Wenn sich Ihre Eingabe in einer Datei befindet, ist '<' nicht erforderlich.< numbers.txt
zeigt, dass es auf stdin genauso gutcat numbers.txt |
funktioniert wie. Und es lehrt keine schlechten Gewohnheiten.Oder Sie können die Zahlen in der Befehlszeile eingeben:
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.
quelle
Folgendes sollte funktionieren (vorausgesetzt, Ihre Nummer ist das zweite Feld in jeder Zeile).
quelle
Einzeiler im Schläger:
quelle
C (nicht vereinfacht)
quelle
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
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:
Der Codeblock zum Summieren jeder Zeile würde also ungefähr so aussehen:
Das ist, wenn Sie sie nur Zeile für Zeile summieren wollten. Jedoch für insgesamt jede Nummer in der Datendatei
Übrigens, wenn ich etwas schnell auf dem Desktop tun muss, benutze ich Folgendes:
quelle
$()
?