7

Right now, I'm trying to nest one bash function call inside another function call (so that the output of one function is used as the input for another function). Is it possible to nest function calls in bash, as I'm trying to do here?

First, I defined these two functions:

returnSomething()
{
    return 5;
}

funky ()
{
  echo $1;
}

Then, I tried to use the output of one function as the input for the other function. However, this next statement doesn't print the output of returnSomething. Instead, it prints nothing at all.

funky $returnSomething; #Now I'm trying to use the output of returnSomething as the input for funky.
5
  • Try just funky returnSomething. $returnSomething is a variable, not a call to the function.
    – fedorqui
    Commented May 1, 2013 at 20:08
  • 1
    see this
    – Wrikken
    Commented May 1, 2013 at 20:09
  • 1
    funky $(returnSomething)
    – Kevin
    Commented May 1, 2013 at 20:09
  • 1
    @Kevin This doesn't seem to make any difference: it still prints nothing at all. Commented May 1, 2013 at 20:12
  • @fedorqui In that case, it would only print the string returnSomething to the console. Commented May 1, 2013 at 20:13

3 Answers 3

10

You have two problems. One is that return does not set the output of a function, but rather its exit status (zero for success, nonzero for failure). For example, echo foo will output foo (plus a newline), but has an exit status of 0. To control output, use echo or printf:

function returnSomething ()     # should actually be outputSomething
{
    echo 5
}

The other problem is that $returnSomething (or ${returnSomething}) gives the value of a variable named returnSomething:

x=5          # sets the variable x
echo "$x"    # outputs 5

To capture the output of a command, use the notation $(...) (or `...`, but the latter is trickier). So:

function funky ()
{
    echo "$( "$1" )"
}
funky returnSomething    # prints 5

or just:

function funky ()
{
    "$1"          # runs argument as a command
}
funky returnSomething    # prints 5

By contrast, if you do want to capture the exit status of a command, use the special shell parameter ? (which is set to the exit status of a command when it completes):

function returnSomething ()
{
    return 5
}
function funky ()
{
    "$1"          # runs argument as a command
    echo "$?"     # prints its exit status
}
funky returnSomething    # prints 5
12
  • 1
    I still haven't figured out how to nest one function call (with parameters) inside another function call. For example, (sampleFunction2 (sampleFunction1 "Parameter for sample function 1")) produces syntax error near unexpected token sampleFunction1'. Is it possible to make nested function calls like this one? Commented Aug 4, 2013 at 5:01
  • @AndersonGreen: I'm not sure I understand what you're asking; Bash commands support a greater variety of possible interactions than functions in other languages, so there are multiple ways to combine them that could all be called "nesting". My best guess is, maybe you want the output of the command sampleFunction1 "Parameter for sample function 1" to be captured (instead of going to the console, as it normally would), and you want that output to be passed as an argument (a parameter) to the function sampleFunction2. Is that right? If so, you can write (continued)
    – ruakh
    Commented Aug 4, 2013 at 5:22
  • (continued) sampleFunction2 "$(sampleFunction1 "Parameter for sample function 1")".
    – ruakh
    Commented Aug 4, 2013 at 5:22
  • 1
    @AndersonGreen: By the way, all of this is explained in detail in the Bash Reference Manual; see gnu.org/software/bash/manual/bashref.html#Command-Substitution.
    – ruakh
    Commented Aug 5, 2013 at 21:23
  • 1
    @AndersonGreen: Regarding double-quotes: it's always a good idea to wrap expansions such as $(...) in double-quotes, so that even if they misbehave and output something different than you expect, you can at least be sure they'll end up as the right number of parameters. (Consider something like cp foo.txt bar.txt $(baz), which is supposed to copy foo.txt and bar.txt into the directory that baz says to -- but if baz (say) errors out and doesn't print any directory at all, then this will overwrite bar.txt with a copy of foo.txt.)
    – ruakh
    Commented Aug 6, 2013 at 0:16
3

Bash substitutes $(command) with the output of command, so you can use funky $(returnSomething) to pass funky the output of returnSomething. However, it looks like you're misunderstanding return in bash; the return value is a number that indicates whether the call was successful. The way to get the return status of the last process in bash is $?:

returnSomething
funky $?
4
  • Does this mean that it's basically impossible for a function in Bash to return any kind of non-integer value? Commented May 1, 2013 at 20:18
  • Yes, you have to print it and capture the output, or set a variable (though there are a number of gotchas around that)
    – Kevin
    Commented May 1, 2013 at 20:20
  • What are those "gotchas", specifically? Commented May 1, 2013 at 20:20
  • If you put a call in a subshell (either as part of a pipe, an explicit subshell, or a $(...) subshell), it won't affect the caller's environment. This especially gets people in loops. You have to declare the variable before the function.
    – Kevin
    Commented May 1, 2013 at 20:50
0

How about this:

function foo() { echo one two three; }
function bar() { echo foo #1: $1 }
bar $( foo ) # ==> foo #1: one

The above has problem, thanks to Anderson for pointing it out. Here is an update:

function foo() { echo one two three; }
function bar() { echo foo $1; }
bar $( foo )
0

Not the answer you're looking for? Browse other questions tagged or ask your own question.