I have a text file with the structure shown below. I'd like to join them into one column (sum them arithmetically and save as a one column).
file structure:
1 4 1 4
2 5 2 5
3 6 3 6
this what I'd like to get:
10
14
18
For most purposes, I think it's best to use an external program such as AWK or Perl (see cnicutar's answer for an AWK approach); but if you prefer, you can do this in pure Bash, as follows:
while read -a arr ; do
i=0
for field in ${arr[*]} ; do
(( i += field ))
done
echo $i
done < input-file.txt > output-file.txt
Or more tersely — but also more hackishly — you could write:
while read ; do
echo $(( ${REPLY//$'\t'/+} ))
done < input-file.txt > output-file.txt
(the latter is roughly equivalent to the (also hackish) sed-based approaches of various other answers).
arr adds anything nonpiratey to the first solution. You could just as well use while read -r; do i=0; for field in $REPLY; do ..., effectively deferring the word splitting from read to for. An alternative for the second solution (for which +1): echo $(($(printf %s+ $REPLY)0)); that works with arbitrary whitespace, including trailing whitespace.How about this:
awk '{ x=0; for(i = 1; i <= NF; i++) x += $i; print x }' file
@cnicutar gave a standard awk solution, I just add a sed one-liner (with bc) for fun:
kent$ cat f
1 4 1 4
2 5 2 5
3 6 3 6
kent$ sed 's/ \+/+/g' f|bc
10
14
18
the \+ in sed line is just in case your columns are separated by multi-spaces.
as @ruakh suggested, sed 's/[[:space:]]\+/+/g' f|bc is more generic and reliable.
sed solution is the best so far. It involves only one invocation, doesn't break on consecutive spaces and doesn't use nonstandard syntax. The only improvement I can think of would be to trim leading and trailing space first.[[:space:]] is anyway reliable. I will change the answerUse sed to replace whitespaces with pluses, then bc to get the results:
sed 's/\s\+/+/g' input | bc
\s is non-standard and will not necessarily be available on non-GNU sed. Using [[:space:]] would be equivalent.Alternatively (the awk solution is better, but it's nice too know that there are alternatives :))
sed 's/ /+/g' test.txt | sed -E 's/^(.*)$/echo $((\1))/' | bash