RSS Feed Share on Twitter

Buy this tutorial as a PDF for only $5

All Shell Scripting Tips

18 Oct 2017

Return codes, Functions, and the number 255

The problem with using shell functions to return integers

In most languages, you would write a function to return the square of an integer like this:

private int square(int n) {
  return n*n;

This Java code would work fine; The Shell script would look like this; I've added a couple of test cases, too:


square() {
  return $(($1 * $1))

for n in 4 8 15 16 17
  echo -n "The square of $n is: "
  square $n
  echo $?  # The return code is passed back as $?
exit 12345

The Shell script would print these results:

$ ./
The square of 4 is: 16
The square of 8 is: 64
The square of 15 is: 225
The square of 16 is: 0
The square of 17 is: 33
$ echo $?

The observant reader will have spotted that it works fine up to, and including, 15*15 = 225.

16*16 is clearly not zero; it is 256.

And 17*17 is 289, not 33.

These wrong results are 256 below their expected values. That's because the return code from a shell function (and from any Unix/Linux program) is a single byte; it has a value between 0 and 255. So 256 gets wrapped around to zero again. 289 is 33 more than 256, so it gets wrapped to 33.

Because the whole script ends with "exit 12345", the return code from the script is 57 (that's 12345 modulo 256, aka 12345%256). But not 12345.

The Solution

Oddly, the solution here, is to acknowledge that the shell really treats all variables as strings, until it is forced to do otherwise - for example, when it is forced to make a numerical comparison, such as:
  if [ "$a" -gt "$b" ]; then ...

So if you echo the result back as a string, this square function will work fine.

In the code below, the syntax: "$(( expression ))" tells the shell to evaluate expression, and return the result.

(It would also be possible (and probably more compatible across shell implementations) to use: "expr $1 \* $1" (the "*" has to have the backslash, or the shell would interpret it as 'all filenames in the current directory'), but that does involve spawning the external expr program, rather than keeping it all in the bash process.)

In the main code which calls the square function, instead of the result coming to the variable "$?", it is returned as standard output, so we catch its content by saying: "result=$(square $n)" - this catches the output and stores it in the $result variable.


square() {
  echo $(($1 * $1))

for n in 4 8 15 16 17
  echo -n "The square of $n is: "
  result=$(square $n)
  echo $result  # The return code is passed back as $?

exit 12345

The return code from the script, 12345, will only ever be seen as 57, because that is how Unix (and therefore Linux) works. The return code from a program is only ever a single byte.

And it's all smarter than this Java implementation by some ill-informed Java coder, as found somewhere on the internet (the guilty shall remain nameless):


Appreciate this site? Please consider making a donation:


Books and eBooks


You can mail me with this form. If you expect a reply, please ensure that the address you specify is valid. Don't forget to include the simple addition question at the end of the form, to prove that you are a real person!

You can buy the content of this Shell Scripting Tutorial as a PDF!