Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

Suppose I have

export MY_VAR=0

in ~/.bashrc.

I have an opened gnome terminal, and in this terminal, I change $MY_VAR value to 200. So, if I do

echo $MY_VAR

in this terminal, 200 is shown.

Now, I opened another tab in my gnome terminal, and do

echo $MY_VAR

...and instead of 200, I have 0.

What should I do to persist the 200 value when a terminal modifies an environment variable, making this modification (setting to 200) available to all subsequent sub shells and such? Is this possible?

share|improve this question

4 Answers 4

up vote 8 down vote accepted

A copy of the environment propagates to sub-shells, so this works:

$ export MY_VAR=200
$ bash
$ echo $MY_VAR
200

but since it's a copy, you can't get that value up to the parent shell — not by changing the environment, at least.

It sounds like you actually want to go a step further, which is to make something which acts like a global variable, shared by "sibling" shells initiated separately from the parent — like your new tab in Gnome Terminal.

Mostly, the answer is "you can't, because environment variables don't work that way". However, there's another answer, which is, well, you can always hack something up. One approach would be to write the value of the variable to a file, like ~/.myvar, and then include that in ~/.bashrc. Then, each new shell will start with the value read from that file.

You could go a step further -- make ~/.myvar be in the format MYVAR=200, and then set `PROMPT_COMMAND=source ~/.myvar', which would cause the value to be re-read every time you get a new prompt. It's still not quite a shared global variable, but it's starting to act like it. It won't activate until a prompt comes back, though, which depending on what you're trying to do could be a serious limitation.

And then, of course, the next thing is to automatically write changes to ~/.myvar. That gets a little more complicated, and I'm going to stop at this point, because really, environment variables were not meant to be an inter-shell communication mechanism, and it's better to just find another way to do it.

share|improve this answer
4  
I can hear the shell squealing under the torture –  Iain Feb 28 '11 at 18:58
    
Yeah sorry. That's why I stopped. :) –  mattdm Feb 28 '11 at 19:08
    
"which is to make something which acts like a global variable" - Well, indeed, that's what I was trying to acomplish. The ~/.myvar isn't pretty, but it works. Do you have another suggestion? –  Somebody still uses you MS-DOS Feb 28 '11 at 19:11
2  
Well, let's step back a bit. Why do you want a global variable? –  mattdm Feb 28 '11 at 19:12
1  
@mattdm: I have some "bureaucracies" that I have to obey. One of them is a bunch of codes I need to commit along with a comment. These codes are, now, in a folder hierarchy (home/user/projects/projectcode/code1/code2). I made a function that extracts code1 and code2 to env vars (so when I need to do an activity, I just call the function inside the dir with the codes), and them, when commiting, I use vim and there are some functions that read these vars and put in a comment automatically. I think using files for that can be a solution. –  Somebody still uses you MS-DOS Feb 28 '11 at 20:24

When I just have googled this question up, I was trying to solve the problem of updating state (i.e. shell variables) from out of subshells. So that one could assign variables, say, inside of a pipeline – and the assignment would be transparently visible to the parent.

Off course, this is not possible in a simple way because individual parts of a pipeline are executed in subshells, which are fork'ed from the parent shell and therefore have memory which is copy-on-write view on the parent's memory. However, I supposed that slim and transparent solution could be possible based on "shared memory" sort of IPCs.

And I have even found an implementation of exactly this design... but it's in Perl.

Adding this answer anyway as a possible solution.

share|improve this answer

Suppose I have export MY_VAR=0 in ~/.bashrc.

That's your mistake right there. You should define your environment variables in ~/.profile, which is read when you log in. ~/.bashrc is read each time you start a shell; when you start the inner shell, it overrides MY_VAR. If you hadn't done that, your environment variable would propagate downards.

For more information on ~/.bashrc vs ~/.profile, see my previous posts on this topic.

Note that upward propagation (getting a modified value from the subshell automatically reflected in the parent shell) is not possible, full stop.

share|improve this answer

Don't use environment variables at all. Use files.

To prevent processes from stepping on each other when updating/reading the file, use lockfiles and small front-end updater scripts whose purpose is just updating a file with $1 if it's not locked. Lockfiles are implemented by basically checking if a specific file exists (/var/run/yourscript.lck) and if it does, wait for the file to disappear for a while, and fail if it doesn't. Also you must delete the lockfile when done updating the file.

Be prepared to handle a situation where a script can't update a file because the file is busy.

share|improve this answer
7  
A trick: use directories instead of files for locking, because mkdir works as an atomic test-and-create. –  mattdm Feb 28 '11 at 20:53
1  
If you guys want to talk about locking, then you might as well be using flock(2) –  Ehtesh Choudhury Apr 12 '13 at 23:20
    
@mattdm I found that a symlink ln -s dummy lockfile (even if broken) may work too as it will fail if the symlink already exists. I wonder some way to test if that is truly 100% secure. –  Aquarius Power Aug 18 '13 at 20:26

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.