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:
- Does
function a
return thels
output without thereturn
command? why? - Why is different the
return
command fromfunction c
andfunction d
? - What does the
total: numeric argument required
mean atfunction c
andfunction d
? - 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
CodePudding user response:
So here is a bit of background:
- Unlike other programming languages in shell functions return their status codes to the calling shell and that code is stored in the
$?
system variable. 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!
CodePudding user response:
When you want the output of any function, or script in bash, you 'capture' its output. I say capture since scripts and functions in bash do not return values like functions in other programming languages (like cpp, js, python..). They output what they do to stdout, so if you want the result of another function or script in bash, you need to capture its output. What you did with the $() is called command substitution. What it does is running a sub-shell with what you give it, and outputs it in place, so it is a good way of capturing output of another scripts, or functions, in bash