How do bash return values of functions

Issue

I am trying to understand how do bash functions return values.
I have created the 4 following functions, and I do not understand how it really works:

#test1.sh
#!/bin/bash



function a() {
    ls -la
}

function b() {
    _b=$(ls -la)
}

function c() {
    _c=$(ls -la)
    return $_c
}

function d() {
    _d=$(ls -la)
    return "$_d"
}
echo "A1:"
a
echo "----------"
echo "A2:"
ret_a=$(a)
echo "$ret_a"
echo "----------"
echo "B1:"
b
echo "----------"
echo "B2:"
ret_b="$(b)"
echo "$ret_b"
echo "----------"
echo "C1:"
c
echo "----------"
echo "C2:"
ret_c="$(c)"
echo "$ret_c"
echo "----------"
echo "D1:"
d
echo "----------"
echo "D2:"
ret_d=$(d)
echo "$ret_d"
echo "----------"

When I execute ./test1.sh it provides me the following output:

$ ./test1.sh
A1:
total 20
drwxrwxr-x  2 mayday mayday  4096 jul 15 09:18 .
drwxrwxrwt 29 root     root     12288 jul 15 11:46 ..
-rwxrw-r--  1 mayday mayday   523 jul 15 11:44 test1.sh
----------
A2:
total 20
drwxrwxr-x  2 mayday mayday  4096 jul 15 09:18 .
drwxrwxrwt 29 root     root     12288 jul 15 11:46 ..
-rwxrw-r--  1 mayday mayday   523 jul 15 11:44 test1.sh
----------
B1:
----------
B2:

----------
C1:
./test1.sh: line 15: return: total: numeric argument required
----------
C2:
./test1.sh: line 15: return: total: numeric argument required

----------
D1:
./test1.sh: line 20: return: total 20
drwxrwxr-x  2 mayday mayday  4096 jul 15 09:18 .
drwxrwxrwt 29 root     root     12288 jul 15 11:46 ..
-rwxrw-r--  1 mayday mayday   523 jul 15 11:44 test1.sh: numeric argument required
----------
D2:
./test1.sh: line 20: return: total 20
drwxrwxr-x  2 mayday mayday  4096 jul 15 09:18 .
drwxrwxrwt 29 root     root     12288 jul 15 11:46 ..
-rwxrw-r--  1 mayday mayday   523 jul 15 11:44 test1.sh: numeric argument required

My questions are:

  1. Does function a return the ls output without the return command? why?
  2. Why is different the returncommand from function c and function d?
  3. What does the total: numeric argument required mean at function c and function d?
  4. As summary, If i wanted to create a new function, that take into a variable the result of the ls executed in the previous function, what would be the best approach from the previous ones? i.e:
function ls_printer() {
    return $(ls -la)
}
function ls_printer_reader() {
    _my_variable=ls_printer
    echo "$_my_variable"
}
ls_printer_reader

Solution

So here is a bit of background:

  1. Unlike other programming languages in shell functions return their status codes to the calling shell and that code is stored in the $? system variable.
  2. return is a command which sends a numerical status code to the calling shell. You can read more about it here.

So now lets walk through your code:

function a() {
    ls -la
}

echo "A1:"
a

Basically calling the a function which will give us the same output as ls -la.

echo "A2:"
ret_a=$(a)
echo "$ret_a"

So now your assigning the output of $(a) to the variable ret_a. since $(a) is basically the same as calling the a function this means you are assigning the variable a couple of lines of text (the output of ls -la).
So in conclusion, variable ret_a is just a multi string.

function b() {
    _b=$(ls -la)
}
 
echo "B1:"
b

So, in this time around function b just assigns a value to a variable named _b and it’s value is, once again, the lines of text coming from ls -la.
Nothing is printed to the terminal as variable assignment is silent…

echo "B2:"
ret_b="$(b)"

So now you are assigning the output of $(b) to ret_b. In this case b is executed since you’ve put $(b) in double quotes "" and thus shell can make the substitution.
As explained above, there is no output from the b method and so an empty string is assigned to ret_b. In the end an empty line is printed to the terminal.

function c() {
    _c=$(ls -la)
    return $_c
}

echo "C1:"
c

In function c the variable _c is , once again, assigned the value of $(ls -la) which is a couple lines of strings. After that the function attempts to return a numerical value but fails since you are trying to return a string. What is actually going on is that the function return is passed multiple strings separated by the new-line character then it ignores all lines other then the first – in this case "total". The error "./test1.sh: line 15: return: total: numeric argument required" is printed once c is called.

echo "C2:"
ret_c="$(c)"
echo "$ret_c"

ret_c is assigned the output of function c which in this case is a line of text reading "./test1.sh: line 15: return: total: numeric argument required" and so once echoed this text is the output.

function d() {
    _d=$(ls -la)
    return "$_d"
}

echo "D1:"
d

Function d does the same as function c. The addition of the double quotes here makes the return function to not only process the first line of text but the entire thing as one big string.
So basically the difference is that in function c the return function was only processing the first line of text ("total") and in d the entire output is passed.
Once again you are trying to return a non numeric value and the output is an error message.

ret_d=$(d)
echo "$ret_d"

Lastly ret_d is passed the output of d and echos it. The output was explained above.

Now, for your 4th question:

function ls_printer() {
ls -la
}
function ls_printer_reader() {
    _my_variable=$(ls_printer)
    echo "$_my_variable"
}
ls_printer_reader

If you want an example of returning both strings and numerical values you can read more here.

Hope this helped you!

Answered By – Gil Gottesman

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published