You Can't Modify the Environment of Parent Processes
Pragmatically, no application can change the environment for any process but itself, and exported values are only inherited by a child process at the time the sub-process is spawned. If you know enough about kernel programming to break that truism then you don't need to be asking the question. That means that, for your purposes, you can't export variables to a parent process from a sub-shell or spawned process, nor can you change the environment of a sub-process that has already been spawned.
Helping Other Processes Modify Their Own Environments
So, you can't do what you want directly. Period.
However, if you design your programs in such a way that you can have them read from a file or file descriptor periodically or when signaled then you can edit the file from your spawned process with the expectation that something will occasionally import these values.
For example, if you have a Bash program like:
while true; do
source new_env.sh
# do something with new values
sleep 5
done
then every 5 seconds the loop will import the new_env.sh file and any exports, commands, or variables defined there would become part of the current execution environment. You could also define a trap for SIGUSR1 or SIGUSR2 to read new_env.sh when it receives the signal and have it re-read the file then.
Ruby can do the same thing. You can define traps and loops that modify ENV for the current environment, which will then impact any sub-processes spawned from that point on. You can also serialize environment variables or other data and write them somewhere that can be read by another application. As a key distinction, this isn't allowing Bash or Ruby to directly modify another process' environment; it's simply a form of inter-process communication that could allow another process to modify itself.
Caveats and Safety Concerns
Sourcing files at runtime is a huge security risk, and generally not recommended. You were given an answer that could work, but it's most probably solving the wrong problem. Most likely this is something you should look at from an architectural perspective rather than as an engineering work-around you need to find.
An Example of Reading Configuration Files at Runtime
More generally, the correct way to modify values in a long-running program would be to read whitelisted values from a trusted source like a database or permission-controlled configuration file and then sanitize the inputs at runtime. For example, you might have your Ruby scripts do something like:
require "yaml"
# read file containing a serialized Ruby Hash
# such as {:foo=>1, :bar=>2, :baz=>3}
def config
# read in your key/value store
cfg = YAML.load_file "config.yml"
# limit allowed values for Hash;
# non-whitelisted values like :quux will
# be ignored
whitelist = %i[foo bar baz]
@config.map do |key, value|
# only process whitelisted keys, and sanitize
# the values; in this case, that means coercing
# them to Integer rather than accepting arbitrary
# values
cfg[key] = value.to_i if whitelist.keys.include? key
end
# re-export whatever you now have in @config, and then
# return the Hash
@config.map { ENV[_1] = _2 }
end
loop do
config
# spawn a process, send a signal, or use IPC
# to communicate with something else
sleep 5
end
This is meant as a trivial example, and not intended to be a bulletproof or ideal solution. However, it should give you a general idea of how to do this relatively safely, provided you have control over your configuration file, your whitelist, and that you treat the contents of said file as tainted and ensure that you sanitize and validate any values you read from it before using them.
It doesn't matter what language you're doing this in. You can use Ruby, Bash, Zsh, or whatever else you like. The general principle is the same, though: don't source the configuration file; read it and only process the lines and values you consider safe.