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,543
  • 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,543
  • 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