Buy this tutorial as a PDF for only $5!
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:
#!/bin/bash square() { return $(($1 * $1)) } for n in 4 8 15 16 17 do echo -n "The square of $n is: " square $n echo $? # The return code is passed back as $? done exit 12345download square.sh
The Shell script would print these results:
$ ./square.sh 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 $? 57 $
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.
#!/bin/bash square() { echo $(($1 * $1)) } for n in 4 8 15 16 17 do echo -n "The square of $n is: " result=$(square $n) echo $result # The return code is passed back as $? done exit 12345download square2.sh
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):

Books and eBooks
My Shell Scripting books, available in Paperback and eBook formats.
![]() Shell Scripting Tutorial is this tutorial, in 88-page Paperback and eBook formats. Convenient to read on the go, and to keep by your desk as an ever-present companion. | ![]() Shell Scripting: Expert Recipes for Linux, Bash and more is my 564-page book on Shell Scripting. The first half explains the features of the shell; the second half has real-world shell scripts, organised by topic, with detailed discussion of each script. |
Contact
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!