4

I have a bunch of functions stored in ~/.bash_functions, which is sourced by ~/.bashrc on shell startup. The file exports all the functions like so:

# Find functions in this script based on a grep search, and export them.
grep ^'[[:alnum:]]' ~/.bash_functions |
  grep '()' |
  cut -d'(' -f1 | 
  while read function
do
  export -f "$function"
done
unset function

This works perfectly fine on a local shell, but not via SSH. None of the functions are actually exported (checked using declare -F). However, if I put echo "$function" into the loop, it prints all the function names, so I know the only part of the loop not working is the export line.

The functions get exported properly if I use export -f in the SSH session, or if I add an export -f line for each individual function in the file.

I'm using 14.04 with Bash 4.3.11, and the SSH client is Termux on Android.

Edit: Even if I add declare -F at the bottom of ~/.bash_functions, the functions show as not exported.

Edit: I just realized that in a local session, some of my functions aren't exported, seemingly at random, but I can't find any evidence of an error. I am doing more research...

wjandrea
  • 14,109
  • 4
  • 48
  • 98
  • Where this snippet is located? Why `unset` at the end (although only `function`, without `$` does not make any sense here)? – heemayl Jul 27 '16 at 19:25
  • @heemayl The code snippet is at the bottom of `~/.bash_functions`. If it were anywhere else it would fail because the functions weren't defined. The `unset` part works properly, don't worry about that. – wjandrea Jul 27 '16 at 19:32
  • Post the full snippet of `~/.bash_functions` – heemayl Jul 27 '16 at 19:36
  • That is the full snippet. I'm not sure what you mean. – wjandrea Jul 27 '16 at 19:38
  • You said the functions are defined in `~/.bash_functions` and you have this snippet on the same file? – heemayl Jul 27 '16 at 19:40

1 Answers1

0

Because the while loop is in a pipeline, it is being executed in a subshell. If you log out and log in, you will see that a local session will be affected too (not just SSH). This can be fixed by moving the list into a variable and switching to a for loop:

# Find functions in this script based on a grep search, and export them.
functions="$( grep ^'[[:alnum:]]' ~/.bash_functions |
  grep '()' |
  cut -d'(' -f1 
)"

for function in $functions; do
  export -f "$function"
done
unset -v function functions # Also I added the -v flag to make this only unset variables.
wjandrea
  • 14,109
  • 4
  • 48
  • 98
  • This is incorrect. While you are sourcing files, it can travel any depth of subshells when constructing the environment. Create a file to source another file and in that file define a function and then use the while loop to read the function name and the export, you'll see.. Also you have put a misguided question at the first place.. – heemayl Jul 28 '16 at 14:42
  • @heemayl Excuse me, but you haven't properly read my answer. I understand how sourcing works. I'm saying the *loop* is in a subshell. The issue is now resolved. And how can a question be misguided? – wjandrea Jul 28 '16 at 14:46
  • __This works perfectly fine on a local shell, but not via SSH.__ this is a showkiller.. – heemayl Jul 28 '16 at 14:47
  • Yes, i know the while loop is in a subshell, refer to my comment again and do the test please.. – heemayl Jul 28 '16 at 14:49
  • @heemayl Yes, and I addressed that in my answer. "If you log out and log in, you will see that a local session will be affected too (not just SSH)." (I just edited the sentence.) Logging out and logging back in was not part of the troubleshooting I had tried already, and I had changed the way the export worked while logged in to that same session, so I hadn't noticed a change in local sessions yet. – wjandrea Jul 28 '16 at 14:51
  • @heemayl I'm not going to keep debating this unless you can come up with another reason why this solution works, because this solution does work. – wjandrea Jul 28 '16 at 14:53
  • Like i said, there must be something else that got fixed in the process, not just the subshell-ing (to be sure do the test i mentioned in the earlier comment). Hard to get to a conclusion without seeing the whole file. Also please try to insert the whole file for these kind of issues..good luck.. – heemayl Jul 28 '16 at 14:59
  • @heemayl Wait, I see where you misunderstood: `source` does not traverse subshells. It executes commands from a file *within the current shell* – wjandrea Jul 28 '16 at 15:00
  • The wording probably incorrect, not the idea. Do this, 1) add `source foo.sh` to your `~/.bashrc` 2) In `foo.sh` put `source bar.sh` 3) In `bar.sh` do: `myfunc() { echo FOOBAR ;}; echo myfunc | while read f; do export -f "$f"; done` 4) Now open a new `bash` session and execute `myfunc` 6) what do you get? – heemayl Jul 28 '16 at 15:05
  • Let us [continue this discussion in chat](http://chat.stackexchange.com/rooms/43142/discussion-between-wjandrea-and-heemayl). – wjandrea Jul 28 '16 at 15:06