Reputation: 11704
I have a log file from a web server which looks like this;
1908 462
232 538
232 520
232 517
My task is to total column 1 and column 2 in a bash script. My desired output is;
2604 2037
I know of awk
or sed
which could go a long way to solving my problem but I can't fathom how to actually do it. I've trawled examples on Google but haven't turned up anything useful. Can someone point me in the right direction please?
Upvotes: 0
Views: 1510
Reputation: 58371
These might work for you:
sed ':a;N;s/ \(\S*\)\n\(\S*\) /+\2 \1+/;$!ba;s/ /\n/p;d' file | bc | paste -sd' '
or
echo $(cut -d' ' -f1 file | paste -sd+ | bc) $(cut -d' ' -f2 file| paste -sd+ |bc)
Upvotes: 0
Reputation: 507
Here is a non-awk alternative for you:
echo $( cut -f 1 -d " " log_file | tr '\n' + | xargs -I '{}' echo '{}'0 | bc ) $( cut -f 2 -d " " log_file | tr '\n' + | xargs -I '{}' echo '{}'0 | bc )
Make sure you replace log_file with your own file and that file does not have any extra or unnecessary new lines. If you have such lines then we would need to filter those out using a command like the following:
grep -v "^\s*$" log_file
Upvotes: 0
Reputation: 263197
awk '{a += $1; b += $2} END { print a " " b }' foo.log
(Note the complete lack of error checking.)
EDIT :
Ok, here's a version with error checking:
awk 'BEGIN { ok = 1 } { if (/^ *[0-9]+ +[0-9]+ *$/) { a += $1; b += $2 } else { ok = 0; exit 1 } } END { if (ok) print a, b }' foo.log
If you don't want to accept leading or trailing blanks, delete the two " *"
s in the if statement.
But this is big enough that it probably shouldn't be a one-liner:
#!/usr/bin/awk -f
BEGIN {
ok = 1
}
{
if (/^ *[0-9]+ +[0-9]+ *$/) {
a += $1
b += $2
}
else {
ok = 0
exit 1
}
}
END {
if (ok) print a, b
}
There's still no overflow or underflow checking, and it assumes that there will be no signs. The latter is easy enough to fix; the former would be more difficult. (Note that awk uses floating-point internally; if the sum is big enough, it could quietly lose precision.)
Upvotes: 6