0

I was trying to make a function that all text piped into it get put into a variable. I ran into a problem. Here is a summary so this works (prints "1").

#!/bin/bash
jkl(){
i=1
}
jkl
echo $i

But not this.

#!/bin/bash
jkl(){
i=1
}
echo hel | jkl
echo $i

What’s up with this?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
lnee_94
  • 25
  • 6
  • 1
    Why do you say that the first one works? You're not piping any text into `jkl`. – David Grayson Oct 26 '21 at 21:46
  • 2
    I think I managed to figure out what you were talking about even though you didn't explain it very well. I suspect the `jkl` function in the second example does not succeed in setting the `i` variable because it is probably getting run inside a sub-shell. https://stackoverflow.com/questions/23564995/how-to-modify-a-global-variable-within-a-function-in-bash – David Grayson Oct 26 '21 at 21:52
  • that uses a bunch on you run command to sync – lnee_94 Oct 27 '21 at 01:00
  • 1
    Here are some other Q&As about setting variables in a pipeline: ["assign a value to a variable in a loop"](https://stackoverflow.com/questions/18275596/assign-a-value-to-a-variable-in-a-loop) and ["Local variables after loop exit"](https://stackoverflow.com/questions/2060082/local-variables-after-loop-exit). Those are about loops rather than functions, but that doesn't matter at all; what matters is that they're in pipelines and therefore run in subshells. – Gordon Davisson Oct 27 '21 at 01:21
  • 1
    This is also [BashFAQ #24](https://mywiki.wooledge.org/BashFAQ/024). – Charles Duffy Oct 27 '21 at 02:36

1 Answers1

0

There are some cases where Bash will start a subshell to run your function. If it does that, then the function cannot set variables for the parent shell. You can write echo $BASH_SUBSHELL to see if that code is running in a subshell.

Here is a simple script to demonstrate the issue:

#!/bin/bash
jkl() {
  echo $BASH_SUBSHELL
  i=$BASH_SUBSHELL
}
echo $BASH_SUBSHELL    # 0
jkl                    # 0
echo hel | jkl         # 1 - uses a subshell
echo $(jkl)            # 1 - uses a subshell
echo $i                # 0
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
David Grayson
  • 84,103
  • 24
  • 152
  • 189