Jede Zeile enthält Text und Zahlen in einer Spalte. Ich muss die Summe der Zahlen in jeder Zeile berechnen. Wie kann ich das machen? Danke
example.log enthält:
time=31sec
time=192sec
time=18sec
time=543sec
Die Antwort sollte 784 sein
Jede Zeile enthält Text und Zahlen in einer Spalte. Ich muss die Summe der Zahlen in jeder Zeile berechnen. Wie kann ich das machen? Danke
example.log enthält:
time=31sec
time=192sec
time=18sec
time=543sec
Die Antwort sollte 784 sein
Antworten:
Mit einer neueren Version (4.x) von GNU awk
:
awk 'BEGIN {FPAT="[0-9]+"}{s+=$1}END{print s}'
Mit anderen awk
s versuchen:
awk -F '[a-z=]*' '{s+=$2}END{print s}'
s+0
für den Fall, dass s
leer ist, wird es 0
statt leer gedruckt .
s
leer sein kann. Wenn die Eingabedaten keine Zeilen enthalten (dh wenn überhaupt keine Eingabe erfolgt ). In diesem Fall sind zwei Verhaltensweisen möglich. 1) keine Eingabe => keine Ausgabe oder 2) immer etwas ausgeben, wenn nur 0. Beide Optionen sind je nach Anwendungskontext sinnvoll. Die +0
Adressierung Option 2). Um Option 1) anzusprechen, müssten Sie lieber schreiben END {if(s) print s}
. - Daher ist es nicht sinnvoll, eine der beiden Optionen (für diesen Eckfall ohne Daten) anzunehmen, bis sie in der Frage angegeben sind.
awk -F= '{sum+=$2};END{print sum}'
time=1.4e5sec
Ein weiterer GNU awk
:
awk -v RS='[0-9]+' '{n+=RT};END{print n}'
Eine perl
Eins:
perl -lne'$n+=$_ for/\d+/g}{print$n'
Ein POSIX eins:
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'='
verwenden--field-separator =
man awk
einziger gibt -F fs
und--field-separator fs
-F'='
oder es -F '='
gibt zwei Möglichkeiten, dies zu tun -F fs
(in Ihrem Fall ist fs "="). Ich habe die einfachen Anführungszeichen hinzugefügt, um sicherzustellen, dass das fs von awk richtig gesehen und interpretiert wird, nicht von der Shell (nützlich, wenn das fs zum Beispiel ';' ist)
Jeder hat tolle awk
Antworten gepostet , die ich sehr mag.
Eine Variation von @cuonglm ersetzt grep
durch sed
:
sed 's/[^0-9]//g' example.log | paste -sd'+' - | bc
sed
Streifen alles außer den Zahlen.paste -sd+ -
Befehl verbindet alle Zeilen zu einer einzigen Zeilebc
wertet den Ausdruck ausSie sollten einen Taschenrechner verwenden.
{ tr = \ | xargs printf '[%s=]P%d+p' | dc; } <infile 2>/dev/null
Mit Ihren vier Zeilen, die gedruckt werden:
time=31
time=223
time=241
time=784
Und einfacher:
tr times=c ' + p' <infile |dc
... was druckt ...
31
223
241
784
Wenn Geschwindigkeit das ist, wonach Sie streben, dc
ist es das, was Sie wollen. Traditionell war es bc
der Compiler - und ist es immer noch für viele Systeme.
dc
so nahe wie ich es beurteilen kann. Worüber redest du?
perl
das Standard-Unix-Toolset als Benchmark verwenden - ist es nicht sehr sinnvoll, GNU-Tools zu verwenden, die in einer GNU-Toolchain kompiliert wurden. Alles, was die Leistung von Perl negativ beeinflussen kann, ist auch in all diesen GNU-kompilierten GNU-Utils enthalten. Traurig aber wahr. Sie benötigen ein echtes, einfach aufgebautes, einfaches Toolset, um den Unterschied genau beurteilen zu können. Wie ein Erbstück-Werkzeugkasten, der statisch mit den Bibliotheken der Muslime verknüpft ist - auf diese Weise können Sie das Ein-Werkzeug / Ein-Job-Paradigma mit dem Ein-Werkzeug-um-sie-alle-zu-regieren-vergleichen.
Durch python3,
import re
with open(file) as f:
m = f.read()
l = re.findall(r'\d+', m)
print(sum(map(int, l)))
re.findall
gibt eine Liste von Zeichenketten zurück, dies wird nicht funktionieren
sum(int(e) for e in l)
ist mehr pythonisch.
Reine Bash-Lösung (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.
Kurzfassung:
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