5

My problem is that when I started coding my script I encountered several variable scope issues which resulted in the bad habit of exporting almost all my variables.

Now that my code has got quite large I was contemplating cleaning it and part of that is removing a bunch of useless exports. Unfortunately I'm not sure if my knowledge of variable scope is complete. Even after reading a few pages on the subject.

What I know (and hopefully is right):

1-Exporting a variable makes it's content available to subshell processes:

export myvar="content"

2-Stuff done in parenthesis like this will be affected by removing exports (from what I understand this is the only way to declare / use a subshell):

$(grep "content" <<< $myvar)

3-Variables declared without setting their scope are global:

myvar="content"

4-Since I don't declare any local variables I don't have to worry about causing issues within my functions:

local myvar="i don't use this"

Questions:

1- Is there any point in proceeding with removing the useless exports beside my code not reeking of obvious noobishness?

2- If I do proceed with it, is there anything else I should be aware of that may be affected and break my code? or is there any of my knowledge wrong/incomplete?

3- If you know of a well written (and complete) variable scope reference please share the link.

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
TCZ8
  • 1,069
  • 2
    +1 But: It doesn't seem like a particularly bad habit to me if the script is just being run alone and not sourced, the difference being that when run alone, the scope of the exported variables is limited to the execution, as opposed to sourcing it, which would drag them into and pollute the current shell environment. – goldilocks Jun 17 '14 at 15:06
  • 1
    My suggestion is for orginization. I suggest you put personal scripts in ~/bin and scripts for other users in /usr/local/bin. Second, I suggest you put all your variables into a single file you can source. ~/.variables . You can source that file from .bashrc if needed or scripts (either by sourcing the file or an include depending on your language). – Panther Jun 17 '14 at 15:14

1 Answers1

2

You can remove all exports without any effect at all on exported variables so long as you don't use export to twice evaluate. By twice evaluate I mean:

var1=var2 
export "${var1}=var3"
echo "$var2"
var3

Instead just use:

set -a 

...at the top of the script. All variables defined thereafter will be automatically exported - which would include variables you might not have previously exported. Alternatively you could only set -a for a portion of the script and later set +a to unset it - it could also work as function.

But subshells automatically inherit variable values anyway, so:

var1=value
( echo "$(echo "$var1")" )
value

export makes no difference in that case.

But if your script calls another script, or any other executable that interprets values you've exported and you cease to export them, then those values will no longer be available in their environment. In the following example I use the shell variable $PS1 - which defines the contents of an interactive shell's prompt - to demonstrate how variations on exported variables affect child processes.

export PS1="$(printf "this is another executable\n > ")"
echo exit | sh -i

###OUTPUT###

this is another executable
 > exit
exit

But ...

PS1="$(printf "this is another executable\n > ")"
echo exit | sh -i

###OUTPUT###

sh-4.3$ exit
exit

But then again, if you explicitly declare environment variables while invoking a process...

PS1="$(printf "this is another executable\n > ")"
{
echo exit | PS1=$PS1 sh -i
echo exit | sh -i
}

###OUTPUT###

this is another executable
 > exit
exit
sh-4.3$ exit
exit
mikeserv
  • 58,310
  • 1
    Got a bit confused at first with your examples using PS1 but I get it now. Thanks for answering my question and teaching me about twice evaluating and set +-a – TCZ8 Jun 19 '14 at 18:30
  • 1
    @TCZ8 - There is little difference between declaring a shell variable and an environment variable. Because export is a builtin it declares an environment variable for the process next invoked, but if you don't invoke one that process remains the shell, and so your variable is twice evaluated. And thank you for the feedback, sorry it wasn't clearer at first. – mikeserv Jun 19 '14 at 18:36