We are bringing this Bash Challenge from Facebook to a wider audience on the regular web. This is the 5th installment of this series. The first 4 challenges can be found on our Facebook pages.
Bash Challenge 5
We will show you a terminal screenshot, and ask you to explain why the result is not the one we were expecting. Of course, the most amusing, and most creative, part of the challenge will be to find how to fix the command(s) displayed on the screen to obtain the correct result.
Ready to play? So here is this week’s challenge:
My Bash don’t know how to count [Difficulty level 1]
This week, I have some data file containing integer numbers, one on each line:
cat sample.data 102 071 210 153
And I want to compute the sum of all those numbers:
declare -i SUM=0 while read X ; do SUM+=$X done < sample.data echo "Sum is: $SUM"
Unfortunately, the result I obtain is wrong (the expected result was 536):
Sum is: 522
Your challenge is to find :
- Why that result was wrong?
- How to fix my commands to obtain the correct result?
★ Bonus unicorn point if you can find a solution using only Bash internal commands and/or shell substitutions.
We’re looking forward to read your solutions in the comment section below! Don’t forget to be creative.
To create this challenge, I used:
- GNU Bash, version 4.4.5 (x86_64-pc-linux-gnu)
- Debian 4.8.7-1 (amd64)
- All commands are those shipped with a standard Debian distribution
- No command was aliased
How to reproduce
Here is the raw code we used to produce this challenge. If you run that in a terminal, you will be able to reproduce exactly the same result as displayed in the challenge illustration (assuming you are using the same software version as me):
rm -rf ItsFOSS mkdir -p ItsFOSS cd ItsFOSS cat > sample.data << 'EOT' 102 071 210 153 EOT clear cat sample.data declare -i SUM=0 while read X ; do SUM+=$X done < sample.data echo "Sum is: $SUM"
What was the problem ?
The problem was caused by the
071 value. As you noticed, this number is starting by a
0 — probably to ensure here all data are formatted on three digits. Nothing complicated here, except that … following an unfortunate convention inherited from the C programming language, prefixing an integer by
0 is a way to specify that number is expressed in octal, and not in decimal.
Octal numbers are expressed with digits from
7. Here is a simple conversion table:
This last value is what caused the error when evaluating the sum. The Bash read
071 and interpreted it as an octal number representing the
57 decimal value. You can check that easily:
echo $((071)) 57
How to fix that ?
I can see two main strategies to fix that issue. Either removing the leading zeros. Or finding a way to make the shell understand all my numbers are decimal values.
Removing leading zeros
Here is a simple solution using the
sed external command to remove the leading zeros :
declare -i SUM=0 while read X ; do SUM+=$X done < <(sed -E s/^0+// sample.data) echo "Sum is: $SUM"
(bonus question: why didn’t I used a pipe instead of a process substitution ?)
Specifying explicitly the base
The previous solution is (mostly) straightforward — but the Bash allows us to make things better. Instead of trying to fix the data, we will simply specify explicitly our numbers are expressed in base 10 (decimal), instead of base 8 (octal). You can do that by using the
Compare those three examples:
echo $((071)) # The leading `0` specify the number as octal 57 echo $((8#071)) # We *explicitly* specify base 8 (octal) 57 echo $((10#071)) # We *explicitly* specify base 10 (decimal) 71
To fix my initial command and obtain the correct result, I only have to explicitly specify the base 10 for all my data :
declare -i SUM=0 while read X ; do SUM+=$((10#$X)) done < sample.data echo "Sum is: $SUM"
And here is the correct result. We hope you enjoyed that challenge. Stay tuned for more fun!
Author Bio: I’m Sylvain Leroux, a software engineer by passion, a teacher by vocation. I have 15 years of experience in teaching Computer Science & Information Technologies at all level. I’m a strong advocate of Linux & OpenSource technologies. I founded Yes I Know IT to share that experience with a wider audience through online courses & free videos. Don’t hesitate to reach me on Twitter.