0

So far I have this script:

#!/bin/sh
echo type in some numbers:
read input

From here on I'm stuck. Let's say input=30790148. What I want to do is add all of those integers up to get 3+0+7+9+0+1+4+8=32. How can I accomplish this?

Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
  • [relevant QA](https://stackoverflow.com/questions/7578930/bash-split-string-into-character-array) – Lucas Wieloch Oct 30 '18 at 12:47
  • 1
    How would you do it mathematically? – Dominique Oct 30 '18 at 12:47
  • Sounds like a homework question... [How do I ask homework questions on Stack Overflow](https://www.google.com/search?q=how+do+I+ask+homework+questions+on+Stack+Overflow). You are expected to make an effort. – jww Oct 30 '18 at 23:18

5 Answers5

4

Another way not using external tools:

read -p "Type some number: " num
for((i=0;i<${#num};i++)); do ((sum+=${num:i:1})); done

echo "$sum"
mickp
  • 1,679
  • 7
  • 23
  • What is it doing: `${num:i:1}`. Seems like a number splitter, shifting one decimal -1- to the right by adding one to each fixed position `i` – Timo Jul 05 '21 at 19:35
  • 1
    @Timo It is a syntax for substrings. It means "return 1 character starting at ith character". Since `$num` is a "string", `${num:i:1}` is `bash`'s equivalent of `num[i]` in other languages. – mickp Jul 12 '21 at 08:23
  • Why not use $i here: `((sum+=${num:i:1}))` – Timo Jul 12 '21 at 18:43
  • It's not mandatory to use `$` in the arithmetic expansion `(( expr ))`. From manual: `...shell variables may also be referenced by name without using the parameter expansion syntax.` – mickp Jul 12 '21 at 18:50
  • ok, Using `((sum+=${num:i}))` without `1` will be a right shift by one reducing the array to the right. – Timo Jul 12 '21 at 19:00
2

There are two core utilities, fold and paste, which you can use here (illustrated for input=12345):

fold -w1 <<< $input | paste -sd+ - | bc
  • fold -w1 wraps the input line to a width of 1 character:

    $ fold -w1 <<< $input
    1
    2
    3
    4
    5
    
  • paste -sd+ - merges the input sequentially (-s), i.e., into a single line, with a + delimiter (-d+), reading from standard input (the final -; optional for GNU paste):

    $ fold -w1 <<< $input | paste -sd+ -
    1+2+3+4+5
    
  • bc then calculates the sum:

    $ fold -w1 <<< $input | paste -sd+ - | bc
    15
    
Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
1

This one using sed and bc

echo "12345" | sed -e 's/\(.\)/\1\+0/g' | bc

It's a bit hackish though since the +0 is not intuitive

Edit: Using & from @PaulHodges' answer, this would shorten to:

echo "12345" | sed 's/./&+0/g' | bc
ssemilla
  • 3,900
  • 12
  • 28
  • This works fine with `bc`, but watch out with prepending zeroes to numbers; in some places, the number will suddenly be interpreted as octal. – Benjamin W. Oct 30 '18 at 13:43
  • Yeah, it's really abusing the fact that `bc` will interpret everything here as decimal. I was gunning for the shortest code possible e.g. `sed 's/./&+0/g' | bc` – ssemilla Oct 30 '18 at 13:45
  • I can't think of anything right now, but imagine a tool that got fed `1+02+09+0`. Since `09` is not a valid octal number, it would definitely error out. – ssemilla Oct 30 '18 at 13:53
  • Sorry, figured out what you meant and deleted my comment, lol – Paul Hodges Oct 30 '18 at 13:54
0

This awk one-liner may help you:

awk '{for(i=1;i<=NF;i++)s+=$i}END{print s}' FS="" <<< yourString

for example:

kent$  awk '{for(i=1;i<=NF;i++)s+=$i}END{print s}' FS=""<<< "123456789" 
45     
Kent
  • 189,393
  • 32
  • 233
  • 301
0

With sed and bc -

input=30790148; echo $input | sed 's/[0-9]/&+/g; s/$/0/;' | bc

If you don't have GNU sed you might need to line break the commands instead of using a semicolon.

input=30790148;
echo $input | 
  sed '
     s/[0-9]/&+/g
      s/$/0/
  ' | bc
Paul Hodges
  • 13,382
  • 1
  • 17
  • 36