how to export VARs from a subshell to a parent shell?

I have a Korn shell script

#!/bin/ksh
# set the right ENV
case $INPUT in
abc)
  export BIN=${ABC_BIN}
  ;;
  def)
  export BIN=${DEF_BIN}
  ;;
  *)
  export BIN=${BASE_BIN}
  ;;
esac
# exit 0 <- bad idea for sourcing the file

now these VARs are export'ed only in a subshell, but I want them to be set in my parent shell as well, so when I am at the prompt those vars are still set correctly.

I know about

. .myscript.sh

but is there a way to do it without 'sourcing'? as my users often forget to 'source'.


EDIT1: removing the "exit 0" part - this was just me typing without thinking first

EDIT2: to add more detail on why do i need this: my developers write code for (for simplicity sake) 2 apps : ABC & DEF. every app is run in production by separate users usrabc and usrdef, hence have setup their $BIN, $CFG, $ORA_HOME, whatever - specific to their apps.

so

  • ABC's $BIN = /opt/abc/bin # $ABC_BIN in the above script
  • DEF's $BIN = /opt/def/bin # $DEF_BIN

etc.

now, on the dev box developers can develop both ABC and DEF at the same time under their own user account 'justin_case', and I make them source the file (above) so that they can switch their ENV var settings back and forth. ($BIN should point to $ABC_BIN at one time and then I need to switch to $BIN=$DEF_BIN)

now, the script should also create new sandboxes for parallel development of the same app, etc. this makes me to do it interactively, asking for sandbox name, etc.

  • /home/justin_case/sandbox_abc_beta2
  • /home/justin_case/sandbox_abc_r1
  • /home/justin_case/sandbox_def_r1

the other option i have considered is writing aliases and add them to every users' profile

  • alias 'setup_env=. .myscript.sh'

and run it with

  • setup_env parameter1 ... parameterX

this makes more sense to me now


Solution 1:

I think it is a "no can do" sort of problem...

First -- you wouldn't want to source that script because of the exit 0 at the end.

Second, no unix child process can directly change the environment of the parent. Otherwise all sorts of crazy things would be possible.

Could you add something to their environment with the default profile or bashrc files, or could you write a wrapper for whatever program it is they are trying to run?

Allow me to elaborate on the "wrapper" concept.

Let's say you want to run the program snoopy with either PROD or DEV in environment variable "OPTIONS" depending on if you want production or development. IF it isn't set, let's say snoopy does something zany like wipe out the database for production and development...

rename "snoopy" to snoopy.bin (or .snoopy.bin)

then put a script in that same location named "snoopy" that contains this:

#!/bin/sh

export OPTIONS

case "$OPTIONS" 
in
  PROD) ;;
  DEV) ;;
  *) OPTIONS=DEV ;;
esac

#the binary is actually named snoopy.bin 

exec "$0.bin" "$@"

If you don't want to muck with the actual file, put this script somewhere in the filesystem that will be ahead of the actual snoopy program in the user's PATH and have a full path to the binary in the script's exec statement...

Solution 2:

The answer is sourcing. Sourcing allows you to include variables in a script in the current shell, but never a parent of that. It is true, you have to be careful not to use any exit command or similar, because that would close your current shell.

You can source a script by using the ".", i.e.

. ./myscript.ksh

Solution 3:

Maybe if you try...

#!/bin/bash

mknod fifo p

(
       echo 'value' > fifo &
)

VARIABLE=`cat fifo`
rm fifo

It's not exactly variable exporting, but it can provide basic communication with the parent process.

Solution 4:

OK, don't laugh now. Very quick and very dirty solution is to add

echo "Please copy and paste this command:"
echo ""
echo "export BIN=\"$BIN\""

to your script.

Another approach. Just exec a subordinate $SHELL in your script, maybe with a different prompt (change $PS1 to notify users under which environment they are working to reduce confusion).

Another approach (my favorite). Users forget to source your script, why is that? Sourcing is precisely the standard way to go. Maybe a good way of reminding them is to remove the first line (#!/bin/sh) and then chmod a-x it. It can be still sourced after that, but it obviously cannot be mistakenly executed.

Rant: All in all, I feel you have had a strange idea in the first place. Maybe not strange... I would say somewhat non-Unix in style. I've never ever needed to export environment to parent in my life. I saw once a similar situation - login .profile asking which of three different environments to set for a single oracle account. Bad idea, in the end it turned out that users preferred to migrate to sudo (they sudo'd to three different oraxxx accounts). What are you trying to achieve, if I may ask?