2

I wrote the following script:

bar() {
        echo $(foo) >&2
        echo "bar" >&2
        echo $VARIABLE >&2
}

foo() {
        echo "foo" >&2
        VARIABLE="test"
        echo $VARIABLE >&2
}
bar

The output is

foo
test

bar

But if I wrote this:

bar() {
        foo
        echo "bar" >&2
        echo $VARIABLE >&2
}

foo() {
        echo "foo" >&2
        VARIABLE="test"
        echo $VARIABLE >&2
}
bar

It prints what I need:

foo
test
bar
test

The question is that I need to send foo's result to &2 yet I need the VARIABLE value that was set when calling to foo. How to do this in bash?

cxw
  • 16,685
  • 2
  • 45
  • 81
Some Name
  • 8,555
  • 5
  • 27
  • 77

1 Answers1

3

Bash runs $() in a subshell, so the assignment to VARIABLE inside $(foo) is thrown away when the $() ends. That is why the variable is not preserved.

Standard input/output/error are always available unless you change them. Therefore, you should be able to do:

bar() {
        foo >&2             # <-- redirect foo's output
        echo "bar" >&2
        echo $VARIABLE >&2
}

Explanation

You can often replace uses of echo $(something) and similar constructions, such as something | cat. In your case:

  • foo produces output to stdout
  • $() copies from stdout to the command line
  • echo copies from the command line to stdout (!!)
  • >&2 redirects from stdout to stderr

The echo $() sequence has the net effect of copying from stdout to stdout :) , so you can just eliminate it.*

* But in other cases, you might want echo $(), e.g., if you are using $() for its side-effects, or if you are deliberately invoking a subshell to protect yourself from variables being changed by what you're executing. However, I think those cases are probably not common.

cxw
  • 16,685
  • 2
  • 45
  • 81
  • Works, cool, thank you. But I have once more question. How about assigning `foo`'s result to a variable? `RETVAL=foo` does not call foo at all. – Some Name May 19 '18 at 16:48
  • Sure! That's actually a separate question :) . `RETVAL="$(foo)"` (note the double-quotes!) will do that, if you remove the `>&2` inside `foo()`. Try it out and post a new question if you have trouble. Happy hacking! – cxw May 19 '18 at 16:49
  • 1
    By the way, please don't forget to accept answers to your questions (the checkmark) if your problem has been solved - I see from your profile that a number of your questions have well-voted answers, but no accepted answers. Don't leave us hanging! :D – cxw May 19 '18 at 16:51
  • @SomeName Of course, once you do `var="$(foo)"` you'll have the same problem of the variable disappearing again. – that other guy May 19 '18 at 16:51
  • Indeed, as @thatotherguy noted. Think about why you're trying to do this. Can you break down your problem in a different way so that you don't have to produce both a variable setting and a value in the same function? – cxw May 19 '18 at 16:58
  • @SomeName Bash is annoying in that the solution to one case is not always applicable to similar code. Just copy&paste your question but with `var=$(foo)` instead of `echo $(foo)` :P – that other guy May 19 '18 at 16:59