Each line contains text and numbers in one column. I need to calculate the sum of the numbers in each row. How can I do that? Thx
example.log contains:
time=31sec time=192sec time=18sec time=543sec The answer should be 784
Each line contains text and numbers in one column. I need to calculate the sum of the numbers in each row. How can I do that? Thx
example.log contains:
time=31sec time=192sec time=18sec time=543sec The answer should be 784
If your grep support -o option, you can try:
$ grep -o '[[:digit:]]*' file | paste -sd+ - | bc 784 POSIXly:
$ printf %d\\n "$(( $(tr -cs 0-9 '[\n*]' <file | paste -sd+ -) ))" 784 With a newer version (4.x) of GNU awk:
awk 'BEGIN {FPAT="[0-9]+"}{s+=$1}END{print s}' With other awks try:
awk -F '[a-z=]*' '{s+=$2}END{print s}' s+0 in case where s is empty, it will print 0 instead of empty. s can be empty; if the input data contains no lines (i.e. if there is no input at all). In that case there are two behaviours possible; 1) no input => no output, or 2) always output something, if only 0. Both are sensible options depending on the application context. The +0 is addressing option 2). To address option 1) you'd rather have to write END {if(s) print s}. - Therefore it makes no sense to assume either option (for this corner case of no data) until it is specified by the question. awk -F= '{sum+=$2};END{print sum}' time=1.4e5sec Another GNU awk one:
awk -v RS='[0-9]+' '{n+=RT};END{print n}' A perl one:
perl -lne'$n+=$_ for/\d+/g}{print$n' A POSIX one:
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'=' instead of --field-separator = man awk only gives -F fs and --field-separator fs -F'=' or -F '=' are 2 ways of doing the -F fs (fs is "=" in your case) . I added the singlequotes to ensure the fs is properly seen & interpreted by awk, not the shell (usefull if the fs is ';' for example) Everyone has posted awesome awk answers, which I like very much.
A variation to @cuonglm replacing grep with sed:
sed 's/[^0-9]//g' example.log | paste -sd'+' - | bc sed strips everything except for the numbers.paste -sd+ - command joins all the lines together as a single linebc evaluates the expressionYou should use a calculator.
{ tr = \ | xargs printf '[%s=]P%d+p' | dc; } <infile 2>/dev/null With your four lines that prints:
time=31 time=223 time=241 time=784 And more simply:
tr times=c ' + p' <infile |dc ...which prints...
31 223 241 784 If speed is what you're after then dc is what you want. Traditionally it was bc's compiler - and still is for many systems.
dc as near as I can tell. What are you talking about? perl v the standard unix toolset - it really doesn't make much sense if you use GNU tools compiled on a GNU toolchain. All of the bloat that can negatively affect Perl's performance is also in all of those GNU-compiled GNU utils. Sad but true. You need a real, simply built, simple toolset to accurately judge the difference. Like an heirloom-toolchest set statically linked against musl libs for instance - in that way you can bench the one-tool/one-job paradigm vs the one-tool-to-rule-them-all one. Through python3,
import re with open(file) as f: m = f.read() l = re.findall(r'\d+', m) print(sum(map(int, l))) re.findall returns a list of strings, this is not going to work sum(int(e) for e in l) is more pythonic. Pure bash solution (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. Short version:
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