Can I export a variable to the environment from a Bash script without sourcing it? - bash

Suppose that I have this script:
export.bash:
#! /usr/bin/env bash
export VAR="HELLO, VARIABLE"
When I execute the script and try to access to the $VAR, I don't get any value!
echo $VAR
Is there a way to access the $VAR by just executing export.bash without sourcing it?

Is there any way to access to the $VAR by just executing export.bash without sourcing it ?
Quick answer: No.
But there are several possible workarounds.
The most obvious one, which you've already mentioned, is to use source or . to execute the script in the context of the calling shell:
$ cat set-vars1.sh
export FOO=BAR
$ . set-vars1.sh
$ echo $FOO
BAR
Another way is to have the script, rather than setting an environment variable, print commands that will set the environment variable:
$ cat set-vars2.sh
#!/bin/bash
echo export FOO=BAR
$ eval "$(./set-vars2.sh)"
$ echo "$FOO"
BAR
A third approach is to have a script that sets your environment variable(s) internally and then invokes a specified command with that environment:
$ cat set-vars3.sh
#!/bin/bash
export FOO=BAR
exec "$#"
$ ./set-vars3.sh printenv | grep FOO
FOO=BAR
This last approach can be quite useful, though it's inconvenient for interactive use since it doesn't give you the settings in your current shell (with all the other settings and history you've built up).

In order to export out the VAR variable first, the most logical and seemly working way is to source the variable:
. ./export.bash
or
source ./export.bash
Now when echoing from the main shell, it works:
echo $VAR
HELLO, VARIABLE
We will now reset VAR:
export VAR=""
echo $VAR
Now we will execute a script to source the variable then unset it:
./test-export.sh
HELLO, VARIABLE
--
.
The code: file test-export.sh
#!/bin/bash
# Source env variable
source ./export.bash
# echo out the variable in test script
echo $VAR
# unset the variable
unset VAR
# echo a few dotted lines
echo "---"
# now return VAR which is blank
echo $VAR
Here is one way:
Please note: The exports are limited to the script that execute the exports in your main console - so as far as a cron job I would add it like the console like below... for the command part still questionable: here is how you would run in from your shell:
On your command prompt (so long as the export.bash file has multiple echo values)
IFS=$'\n'; for entries in $(./export.bash); do export $entries; done; ./v1.sh
HELLO THERE
HI THERE
File cat v1.sh
#!/bin/bash
echo $VAR
echo $VAR1
Now so long as this is for your usage - you could make the variables available for your scripts at any time by doing a Bash alias like this:
myvars ./v1.sh
HELLO THERE
HI THERE
echo $VAR
.
Add this to your .bashrc file:
function myvars() {
IFS=$'\n';
for entries in $(./export.bash); do export $entries; done;
"$#";
for entries in $(./export.bash); do variable=$(echo $entries|awk -F"=" '{print $1}'); unset $variable;
done
}
Source your .bashrc file and you can do like the above any time...
Anyhow back to the rest of it...
This has made it available globally then executed the script...
Simply echo it out and run export on the echo!
File export.bash
#!/bin/bash
echo "VAR=HELLO THERE"
Now within script or your console run:
export "$(./export.bash)"
Try:
echo $VAR
HELLO THERE
Multiple values so long as you know what you are expecting in another script using the above method:
File export.bash
#!/bin/bash
echo "VAR=HELLO THERE"
echo "VAR1=HI THERE"
File test-export.sh
#!/bin/bash
IFS=$'\n'
for entries in $(./export.bash); do
export $entries
done
echo "round 1"
echo $VAR
echo $VAR1
for entries in $(./export.bash); do
variable=$(echo $entries|awk -F"=" '{print $1}');
unset $variable
done
echo "round 2"
echo $VAR
echo $VAR1
Now the results
./test-export.sh
round 1
HELLO THERE
HI THERE
round 2
.
And the final final update to auto assign, read the VARIABLES:
./test-export.sh
Round 0 - Export out then find variable name -
Set current variable to the variable exported then echo its value
$VAR has value of HELLO THERE
$VAR1 has value of HI THERE
round 1 - we know what was exported and we will echo out known variables
HELLO THERE
HI THERE
Round 2 - We will just return the variable names and unset them
round 3 - Now we get nothing back
The script:
File test-export.sh
#!/bin/bash
IFS=$'\n'
echo "Round 0 - Export out then find variable name - "
echo "Set current variable to the variable exported then echo its value"
for entries in $(./export.bash); do
variable=$(echo $entries|awk -F"=" '{print $1}');
export $entries
eval current_variable=\$$variable
echo "\$$variable has value of $current_variable"
done
echo "round 1 - we know what was exported and we will echo out known variables"
echo $VAR
echo $VAR1
echo "Round 2 - We will just return the variable names and unset them "
for entries in $(./export.bash); do
variable=$(echo $entries|awk -F"=" '{print $1}');
unset $variable
done
echo "round 3 - Now we get nothing back"
echo $VAR
echo $VAR1

Execute
set -o allexport
Any variables you source from a file after this will be exported in your shell.
source conf-file
When you're done execute. This will disable allexport mode.
set +o allexport

I found an interesting and neat way to export environment variables from a file:
In file env.vars:
foo=test
Test script:
eval `cat env.vars`
echo $foo # => test
sh -c 'echo $foo' # =>
export eval `cat env.vars`
echo $foo # => test
sh -c 'echo $foo' # => test
# a better one. "--" stops processing options,
# key=value list given as parameters
export -- `cat env.vars`
echo $foo # => test
sh -c 'echo $foo' # => test

Another workaround that, depends on the case, it could be useful: creating another bash script that inherits the exported variable. It is a particular case of Keith Thompson's answer, will all of those drawbacks.
File export.bash:
# !/bin/bash
export VAR="HELLO, VARIABLE"
bash
Now:
./export.bash
echo $VAR

The answer is no, but for me I did the following
The script:
myExport
#! \bin\bash
export $1
An alias in my .bashrc file:
alias myExport='source myExport'
Still you source it, but maybe in this way it is more useable and it is interesting for someone else.

Maybe you can add a function in ~/.zshrc or ~/.bashrc.
# set my env
[ -s ~/.env ] && export MYENV=`cat ~/.env`
function myenv() { [[ -s ~/.env ]] && echo $argv > ~/.env && export MYENV=$argv }
Because of the use of a variable outside, you can avoid the use of a script file.

Export environment variables using script file
Problem:
When you run a script, it executes in a child shell and returns back to the parent shell after execution. Exporting variables only works down the child shells, you can't export a child shell's variable back to the parent shell.
Solution:
From your script file invoke a child shell along with variables that you want to export, this will create a new child shell with your variables exported.
script.sh ->
bash -c 'export VAR=variable; exec bash'
: : CIPH3R

I don't think this can be done, but I found a workaround using alias. It will only work when you place your script in your scripts directory. Otherwise your alias will have an invalid name.
The only point to the workaround is to be able to have a function inside a file with the same name and not have to bother sourcing it before using it. Add the following code to file ~/.bashrc:
alias myFunction='unalias myFunction && . myFunction && myFunction "$#"'
You can now call myFunction without sourcing it first.

This workaround is somehow hinted to elsewhere, but maybe not that clearly:
In your script, after setting the variable, start a new shell, rather than return.
My use cases is that I have a number of terminals open and in some of them I want some values for some variables, while in others I want other values.
As using source may be harder to remember, a small advantage of this approach is when it takes a while to realize that you forgot to use source, and you have to start from scratch.
(For me it makes more sense to use source script, as the missing variables are noticed immediately.)

I had similar problem calling ssh-agent -s in a script called by option -e in rsync.
In the script eval $(ssh-agent -s) don't preserve the environment variables for the next call.
rsync -e 'source ssh-check-agent.sh -p 8022' does not work, so I made a workaround. In the script I saved the variables in a temporal file after call ssh-agent like:
echo "export SSH_AUTH_SOCK=$SSH_AUTH_SOCK;" > /tmp/ssh-check-agent.vars
echo "export SSH_AGENT_PID=$SSH_AGENT_PID;" >> /tmp/ssh-check-agent.vars
and after in the script that calls rsync (backup.sh) I call:
source /tmp/ssh-check-agent.vars
The problem is that script that calls rsync must be called by source (source backup.sh).
I know that is not the question (I use two times source), but I put here if someone has similar problem with rsync.

simple naive approach that works:
script 1:
echo "something" > /tmp/myvar
script 2:
myvar=$(cat /tmp/myvar)

If you want to set a variable for the calling shell there is a robust approach using c unix sockets.
The result will be tested like this:
$ ./a.out &
[1] 5363
$ ./b.out 123;a=`./b.out`;echo ${a}
123
[1]+ Done ./a.out
See a.c, b.c, and a.h from my github.

Related

Use bash script to source through multiple .env files at once [duplicate]

Suppose that I have this script:
export.bash:
#! /usr/bin/env bash
export VAR="HELLO, VARIABLE"
When I execute the script and try to access to the $VAR, I don't get any value!
echo $VAR
Is there a way to access the $VAR by just executing export.bash without sourcing it?
Is there any way to access to the $VAR by just executing export.bash without sourcing it ?
Quick answer: No.
But there are several possible workarounds.
The most obvious one, which you've already mentioned, is to use source or . to execute the script in the context of the calling shell:
$ cat set-vars1.sh
export FOO=BAR
$ . set-vars1.sh
$ echo $FOO
BAR
Another way is to have the script, rather than setting an environment variable, print commands that will set the environment variable:
$ cat set-vars2.sh
#!/bin/bash
echo export FOO=BAR
$ eval "$(./set-vars2.sh)"
$ echo "$FOO"
BAR
A third approach is to have a script that sets your environment variable(s) internally and then invokes a specified command with that environment:
$ cat set-vars3.sh
#!/bin/bash
export FOO=BAR
exec "$#"
$ ./set-vars3.sh printenv | grep FOO
FOO=BAR
This last approach can be quite useful, though it's inconvenient for interactive use since it doesn't give you the settings in your current shell (with all the other settings and history you've built up).
In order to export out the VAR variable first, the most logical and seemly working way is to source the variable:
. ./export.bash
or
source ./export.bash
Now when echoing from the main shell, it works:
echo $VAR
HELLO, VARIABLE
We will now reset VAR:
export VAR=""
echo $VAR
Now we will execute a script to source the variable then unset it:
./test-export.sh
HELLO, VARIABLE
--
.
The code: file test-export.sh
#!/bin/bash
# Source env variable
source ./export.bash
# echo out the variable in test script
echo $VAR
# unset the variable
unset VAR
# echo a few dotted lines
echo "---"
# now return VAR which is blank
echo $VAR
Here is one way:
Please note: The exports are limited to the script that execute the exports in your main console - so as far as a cron job I would add it like the console like below... for the command part still questionable: here is how you would run in from your shell:
On your command prompt (so long as the export.bash file has multiple echo values)
IFS=$'\n'; for entries in $(./export.bash); do export $entries; done; ./v1.sh
HELLO THERE
HI THERE
File cat v1.sh
#!/bin/bash
echo $VAR
echo $VAR1
Now so long as this is for your usage - you could make the variables available for your scripts at any time by doing a Bash alias like this:
myvars ./v1.sh
HELLO THERE
HI THERE
echo $VAR
.
Add this to your .bashrc file:
function myvars() {
IFS=$'\n';
for entries in $(./export.bash); do export $entries; done;
"$#";
for entries in $(./export.bash); do variable=$(echo $entries|awk -F"=" '{print $1}'); unset $variable;
done
}
Source your .bashrc file and you can do like the above any time...
Anyhow back to the rest of it...
This has made it available globally then executed the script...
Simply echo it out and run export on the echo!
File export.bash
#!/bin/bash
echo "VAR=HELLO THERE"
Now within script or your console run:
export "$(./export.bash)"
Try:
echo $VAR
HELLO THERE
Multiple values so long as you know what you are expecting in another script using the above method:
File export.bash
#!/bin/bash
echo "VAR=HELLO THERE"
echo "VAR1=HI THERE"
File test-export.sh
#!/bin/bash
IFS=$'\n'
for entries in $(./export.bash); do
export $entries
done
echo "round 1"
echo $VAR
echo $VAR1
for entries in $(./export.bash); do
variable=$(echo $entries|awk -F"=" '{print $1}');
unset $variable
done
echo "round 2"
echo $VAR
echo $VAR1
Now the results
./test-export.sh
round 1
HELLO THERE
HI THERE
round 2
.
And the final final update to auto assign, read the VARIABLES:
./test-export.sh
Round 0 - Export out then find variable name -
Set current variable to the variable exported then echo its value
$VAR has value of HELLO THERE
$VAR1 has value of HI THERE
round 1 - we know what was exported and we will echo out known variables
HELLO THERE
HI THERE
Round 2 - We will just return the variable names and unset them
round 3 - Now we get nothing back
The script:
File test-export.sh
#!/bin/bash
IFS=$'\n'
echo "Round 0 - Export out then find variable name - "
echo "Set current variable to the variable exported then echo its value"
for entries in $(./export.bash); do
variable=$(echo $entries|awk -F"=" '{print $1}');
export $entries
eval current_variable=\$$variable
echo "\$$variable has value of $current_variable"
done
echo "round 1 - we know what was exported and we will echo out known variables"
echo $VAR
echo $VAR1
echo "Round 2 - We will just return the variable names and unset them "
for entries in $(./export.bash); do
variable=$(echo $entries|awk -F"=" '{print $1}');
unset $variable
done
echo "round 3 - Now we get nothing back"
echo $VAR
echo $VAR1
Execute
set -o allexport
Any variables you source from a file after this will be exported in your shell.
source conf-file
When you're done execute. This will disable allexport mode.
set +o allexport
I found an interesting and neat way to export environment variables from a file:
In file env.vars:
foo=test
Test script:
eval `cat env.vars`
echo $foo # => test
sh -c 'echo $foo' # =>
export eval `cat env.vars`
echo $foo # => test
sh -c 'echo $foo' # => test
# a better one. "--" stops processing options,
# key=value list given as parameters
export -- `cat env.vars`
echo $foo # => test
sh -c 'echo $foo' # => test
Another workaround that, depends on the case, it could be useful: creating another bash script that inherits the exported variable. It is a particular case of Keith Thompson's answer, will all of those drawbacks.
File export.bash:
# !/bin/bash
export VAR="HELLO, VARIABLE"
bash
Now:
./export.bash
echo $VAR
The answer is no, but for me I did the following
The script:
myExport
#! \bin\bash
export $1
An alias in my .bashrc file:
alias myExport='source myExport'
Still you source it, but maybe in this way it is more useable and it is interesting for someone else.
Maybe you can add a function in ~/.zshrc or ~/.bashrc.
# set my env
[ -s ~/.env ] && export MYENV=`cat ~/.env`
function myenv() { [[ -s ~/.env ]] && echo $argv > ~/.env && export MYENV=$argv }
Because of the use of a variable outside, you can avoid the use of a script file.
Export environment variables using script file
Problem:
When you run a script, it executes in a child shell and returns back to the parent shell after execution. Exporting variables only works down the child shells, you can't export a child shell's variable back to the parent shell.
Solution:
From your script file invoke a child shell along with variables that you want to export, this will create a new child shell with your variables exported.
script.sh ->
bash -c 'export VAR=variable; exec bash'
: : CIPH3R
I don't think this can be done, but I found a workaround using alias. It will only work when you place your script in your scripts directory. Otherwise your alias will have an invalid name.
The only point to the workaround is to be able to have a function inside a file with the same name and not have to bother sourcing it before using it. Add the following code to file ~/.bashrc:
alias myFunction='unalias myFunction && . myFunction && myFunction "$#"'
You can now call myFunction without sourcing it first.
This workaround is somehow hinted to elsewhere, but maybe not that clearly:
In your script, after setting the variable, start a new shell, rather than return.
My use cases is that I have a number of terminals open and in some of them I want some values for some variables, while in others I want other values.
As using source may be harder to remember, a small advantage of this approach is when it takes a while to realize that you forgot to use source, and you have to start from scratch.
(For me it makes more sense to use source script, as the missing variables are noticed immediately.)
I had similar problem calling ssh-agent -s in a script called by option -e in rsync.
In the script eval $(ssh-agent -s) don't preserve the environment variables for the next call.
rsync -e 'source ssh-check-agent.sh -p 8022' does not work, so I made a workaround. In the script I saved the variables in a temporal file after call ssh-agent like:
echo "export SSH_AUTH_SOCK=$SSH_AUTH_SOCK;" > /tmp/ssh-check-agent.vars
echo "export SSH_AGENT_PID=$SSH_AGENT_PID;" >> /tmp/ssh-check-agent.vars
and after in the script that calls rsync (backup.sh) I call:
source /tmp/ssh-check-agent.vars
The problem is that script that calls rsync must be called by source (source backup.sh).
I know that is not the question (I use two times source), but I put here if someone has similar problem with rsync.
simple naive approach that works:
script 1:
echo "something" > /tmp/myvar
script 2:
myvar=$(cat /tmp/myvar)
If you want to set a variable for the calling shell there is a robust approach using c unix sockets.
The result will be tested like this:
$ ./a.out &
[1] 5363
$ ./b.out 123;a=`./b.out`;echo ${a}
123
[1]+ Done ./a.out
See a.c, b.c, and a.h from my github.

Can I put a breakpoint in shell script?

Is there a way to suspend the execution of the shell script to inspect the state of the environment or execute random commands?
alias combined with eval gives you basic functionality of breakpoints in calling context:
#!/bin/bash
shopt -s expand_aliases
alias breakpoint='
while read -p"Debugging(Ctrl-d to exit)> " debugging_line
do
eval "$debugging_line"
done'
f(){
local var=1
breakpoint
echo $'\n'"After breakpoint, var=$var"
}
f
At the breakpoint, you can input
echo $var
followed by
var=2
then Ctrl-d to exit from breakpoint.
Due to eval in the while loop, use with caution.
Bash or shell scripts do not have such debugging capabilities as other programming languages like Java, Python, etc.
We can put the echo "VAR_NAME=$VAR_NAME" command in the code where we want to log the variable value.
Also, a little bit more flexible solution is to put this code somewhere at the beginning in the shell script we want to debug:
function BREAKPOINT() {
BREAKPOINT_NAME=$1
echo "Enter breakpoint $BREAKPOINT_NAME"
set +e
/bin/bash
BREAKPOINT_EXIT_CODE=$?
set -e
if [[ $BREAKPOINT_EXIT_CODE -eq 0 ]]; then
echo "Continue after breakpoint $BREAKPOINT_NAME"
else
echo "Terminate after breakpoint $BREAKPOINT_NAME"
exit $BREAKPOINT_EXIT_CODE
fi
}
export -f BREAKPOINT
and then later, at the line of code where we need to break we invoke this function like this:
# some shell script here
BREAKPOINT MyBreakPoint
# and some other shell script here
So then the BREAKPOINT function will log some output then launch /bin/bash where we can run any echo or some other shell command we want. When we want to continue running the rest of the shell script (release breakpoint) we just need to execute exit command. If we need to terminate script execution we would run exit 1 command.
There exist solutions like bash-debug.
A poor-man's solution which works for me is the interactive shell.
By adding three lines of code, you can introspect and alter variables as follows:
Let's assume, that you have the script test.bash
A=FOO
export B=BAR
echo $A
echo $B
$ test.bash
FOO
BAR
If you add an interactive shell at line 3, you can look around and inspect variables which have been exported before:
A=FOO
export B=BAR
bash -c "$SHELL"
echo $A
echo $B
$ test.bash
$ echo $A
$ echo $B
BAR
$ exit
FOO
BAR
If you want to see all variables in your interactive shell, you have to add set -a to the preamble of your script, such that all variables and functions are exported:
set -a
A=FOO
export B=BAR
bash -c "$SHELL"
echo $A
echo $B
$ test.bash
$ echo $A
FOO
$ echo $B
BAR
$ exit
FOO
BAR
Note, that you cannot change the variables in your interactive shell. The only solution for me is to source an additional script of variables, which will be sourced rightafter the interactive shell
set -a
A=FOO
export B=BAR
bash -c "$SHELL"
source /tmp/var
echo $A
echo $B
$ test.bash
$ echo "export A=alice" > /tmp/var
$ echo "export B=bob" >> /tmp/var
$ exit
alice
bob

How to import a variable form bash script which will be avaialble globally? [duplicate]

Suppose that I have this script:
export.bash:
#! /usr/bin/env bash
export VAR="HELLO, VARIABLE"
When I execute the script and try to access to the $VAR, I don't get any value!
echo $VAR
Is there a way to access the $VAR by just executing export.bash without sourcing it?
Is there any way to access to the $VAR by just executing export.bash without sourcing it ?
Quick answer: No.
But there are several possible workarounds.
The most obvious one, which you've already mentioned, is to use source or . to execute the script in the context of the calling shell:
$ cat set-vars1.sh
export FOO=BAR
$ . set-vars1.sh
$ echo $FOO
BAR
Another way is to have the script, rather than setting an environment variable, print commands that will set the environment variable:
$ cat set-vars2.sh
#!/bin/bash
echo export FOO=BAR
$ eval "$(./set-vars2.sh)"
$ echo "$FOO"
BAR
A third approach is to have a script that sets your environment variable(s) internally and then invokes a specified command with that environment:
$ cat set-vars3.sh
#!/bin/bash
export FOO=BAR
exec "$#"
$ ./set-vars3.sh printenv | grep FOO
FOO=BAR
This last approach can be quite useful, though it's inconvenient for interactive use since it doesn't give you the settings in your current shell (with all the other settings and history you've built up).
In order to export out the VAR variable first, the most logical and seemly working way is to source the variable:
. ./export.bash
or
source ./export.bash
Now when echoing from the main shell, it works:
echo $VAR
HELLO, VARIABLE
We will now reset VAR:
export VAR=""
echo $VAR
Now we will execute a script to source the variable then unset it:
./test-export.sh
HELLO, VARIABLE
--
.
The code: file test-export.sh
#!/bin/bash
# Source env variable
source ./export.bash
# echo out the variable in test script
echo $VAR
# unset the variable
unset VAR
# echo a few dotted lines
echo "---"
# now return VAR which is blank
echo $VAR
Here is one way:
Please note: The exports are limited to the script that execute the exports in your main console - so as far as a cron job I would add it like the console like below... for the command part still questionable: here is how you would run in from your shell:
On your command prompt (so long as the export.bash file has multiple echo values)
IFS=$'\n'; for entries in $(./export.bash); do export $entries; done; ./v1.sh
HELLO THERE
HI THERE
File cat v1.sh
#!/bin/bash
echo $VAR
echo $VAR1
Now so long as this is for your usage - you could make the variables available for your scripts at any time by doing a Bash alias like this:
myvars ./v1.sh
HELLO THERE
HI THERE
echo $VAR
.
Add this to your .bashrc file:
function myvars() {
IFS=$'\n';
for entries in $(./export.bash); do export $entries; done;
"$#";
for entries in $(./export.bash); do variable=$(echo $entries|awk -F"=" '{print $1}'); unset $variable;
done
}
Source your .bashrc file and you can do like the above any time...
Anyhow back to the rest of it...
This has made it available globally then executed the script...
Simply echo it out and run export on the echo!
File export.bash
#!/bin/bash
echo "VAR=HELLO THERE"
Now within script or your console run:
export "$(./export.bash)"
Try:
echo $VAR
HELLO THERE
Multiple values so long as you know what you are expecting in another script using the above method:
File export.bash
#!/bin/bash
echo "VAR=HELLO THERE"
echo "VAR1=HI THERE"
File test-export.sh
#!/bin/bash
IFS=$'\n'
for entries in $(./export.bash); do
export $entries
done
echo "round 1"
echo $VAR
echo $VAR1
for entries in $(./export.bash); do
variable=$(echo $entries|awk -F"=" '{print $1}');
unset $variable
done
echo "round 2"
echo $VAR
echo $VAR1
Now the results
./test-export.sh
round 1
HELLO THERE
HI THERE
round 2
.
And the final final update to auto assign, read the VARIABLES:
./test-export.sh
Round 0 - Export out then find variable name -
Set current variable to the variable exported then echo its value
$VAR has value of HELLO THERE
$VAR1 has value of HI THERE
round 1 - we know what was exported and we will echo out known variables
HELLO THERE
HI THERE
Round 2 - We will just return the variable names and unset them
round 3 - Now we get nothing back
The script:
File test-export.sh
#!/bin/bash
IFS=$'\n'
echo "Round 0 - Export out then find variable name - "
echo "Set current variable to the variable exported then echo its value"
for entries in $(./export.bash); do
variable=$(echo $entries|awk -F"=" '{print $1}');
export $entries
eval current_variable=\$$variable
echo "\$$variable has value of $current_variable"
done
echo "round 1 - we know what was exported and we will echo out known variables"
echo $VAR
echo $VAR1
echo "Round 2 - We will just return the variable names and unset them "
for entries in $(./export.bash); do
variable=$(echo $entries|awk -F"=" '{print $1}');
unset $variable
done
echo "round 3 - Now we get nothing back"
echo $VAR
echo $VAR1
Execute
set -o allexport
Any variables you source from a file after this will be exported in your shell.
source conf-file
When you're done execute. This will disable allexport mode.
set +o allexport
I found an interesting and neat way to export environment variables from a file:
In file env.vars:
foo=test
Test script:
eval `cat env.vars`
echo $foo # => test
sh -c 'echo $foo' # =>
export eval `cat env.vars`
echo $foo # => test
sh -c 'echo $foo' # => test
# a better one. "--" stops processing options,
# key=value list given as parameters
export -- `cat env.vars`
echo $foo # => test
sh -c 'echo $foo' # => test
Another workaround that, depends on the case, it could be useful: creating another bash script that inherits the exported variable. It is a particular case of Keith Thompson's answer, will all of those drawbacks.
File export.bash:
# !/bin/bash
export VAR="HELLO, VARIABLE"
bash
Now:
./export.bash
echo $VAR
The answer is no, but for me I did the following
The script:
myExport
#! \bin\bash
export $1
An alias in my .bashrc file:
alias myExport='source myExport'
Still you source it, but maybe in this way it is more useable and it is interesting for someone else.
Maybe you can add a function in ~/.zshrc or ~/.bashrc.
# set my env
[ -s ~/.env ] && export MYENV=`cat ~/.env`
function myenv() { [[ -s ~/.env ]] && echo $argv > ~/.env && export MYENV=$argv }
Because of the use of a variable outside, you can avoid the use of a script file.
Export environment variables using script file
Problem:
When you run a script, it executes in a child shell and returns back to the parent shell after execution. Exporting variables only works down the child shells, you can't export a child shell's variable back to the parent shell.
Solution:
From your script file invoke a child shell along with variables that you want to export, this will create a new child shell with your variables exported.
script.sh ->
bash -c 'export VAR=variable; exec bash'
: : CIPH3R
I don't think this can be done, but I found a workaround using alias. It will only work when you place your script in your scripts directory. Otherwise your alias will have an invalid name.
The only point to the workaround is to be able to have a function inside a file with the same name and not have to bother sourcing it before using it. Add the following code to file ~/.bashrc:
alias myFunction='unalias myFunction && . myFunction && myFunction "$#"'
You can now call myFunction without sourcing it first.
This workaround is somehow hinted to elsewhere, but maybe not that clearly:
In your script, after setting the variable, start a new shell, rather than return.
My use cases is that I have a number of terminals open and in some of them I want some values for some variables, while in others I want other values.
As using source may be harder to remember, a small advantage of this approach is when it takes a while to realize that you forgot to use source, and you have to start from scratch.
(For me it makes more sense to use source script, as the missing variables are noticed immediately.)
I had similar problem calling ssh-agent -s in a script called by option -e in rsync.
In the script eval $(ssh-agent -s) don't preserve the environment variables for the next call.
rsync -e 'source ssh-check-agent.sh -p 8022' does not work, so I made a workaround. In the script I saved the variables in a temporal file after call ssh-agent like:
echo "export SSH_AUTH_SOCK=$SSH_AUTH_SOCK;" > /tmp/ssh-check-agent.vars
echo "export SSH_AGENT_PID=$SSH_AGENT_PID;" >> /tmp/ssh-check-agent.vars
and after in the script that calls rsync (backup.sh) I call:
source /tmp/ssh-check-agent.vars
The problem is that script that calls rsync must be called by source (source backup.sh).
I know that is not the question (I use two times source), but I put here if someone has similar problem with rsync.
simple naive approach that works:
script 1:
echo "something" > /tmp/myvar
script 2:
myvar=$(cat /tmp/myvar)
If you want to set a variable for the calling shell there is a robust approach using c unix sockets.
The result will be tested like this:
$ ./a.out &
[1] 5363
$ ./b.out 123;a=`./b.out`;echo ${a}
123
[1]+ Done ./a.out
See a.c, b.c, and a.h from my github.

How can I write a script that causes the equivalent of sourcing a file? [duplicate]

Suppose that I have this script:
export.bash:
#! /usr/bin/env bash
export VAR="HELLO, VARIABLE"
When I execute the script and try to access to the $VAR, I don't get any value!
echo $VAR
Is there a way to access the $VAR by just executing export.bash without sourcing it?
Is there any way to access to the $VAR by just executing export.bash without sourcing it ?
Quick answer: No.
But there are several possible workarounds.
The most obvious one, which you've already mentioned, is to use source or . to execute the script in the context of the calling shell:
$ cat set-vars1.sh
export FOO=BAR
$ . set-vars1.sh
$ echo $FOO
BAR
Another way is to have the script, rather than setting an environment variable, print commands that will set the environment variable:
$ cat set-vars2.sh
#!/bin/bash
echo export FOO=BAR
$ eval "$(./set-vars2.sh)"
$ echo "$FOO"
BAR
A third approach is to have a script that sets your environment variable(s) internally and then invokes a specified command with that environment:
$ cat set-vars3.sh
#!/bin/bash
export FOO=BAR
exec "$#"
$ ./set-vars3.sh printenv | grep FOO
FOO=BAR
This last approach can be quite useful, though it's inconvenient for interactive use since it doesn't give you the settings in your current shell (with all the other settings and history you've built up).
In order to export out the VAR variable first, the most logical and seemly working way is to source the variable:
. ./export.bash
or
source ./export.bash
Now when echoing from the main shell, it works:
echo $VAR
HELLO, VARIABLE
We will now reset VAR:
export VAR=""
echo $VAR
Now we will execute a script to source the variable then unset it:
./test-export.sh
HELLO, VARIABLE
--
.
The code: file test-export.sh
#!/bin/bash
# Source env variable
source ./export.bash
# echo out the variable in test script
echo $VAR
# unset the variable
unset VAR
# echo a few dotted lines
echo "---"
# now return VAR which is blank
echo $VAR
Here is one way:
Please note: The exports are limited to the script that execute the exports in your main console - so as far as a cron job I would add it like the console like below... for the command part still questionable: here is how you would run in from your shell:
On your command prompt (so long as the export.bash file has multiple echo values)
IFS=$'\n'; for entries in $(./export.bash); do export $entries; done; ./v1.sh
HELLO THERE
HI THERE
File cat v1.sh
#!/bin/bash
echo $VAR
echo $VAR1
Now so long as this is for your usage - you could make the variables available for your scripts at any time by doing a Bash alias like this:
myvars ./v1.sh
HELLO THERE
HI THERE
echo $VAR
.
Add this to your .bashrc file:
function myvars() {
IFS=$'\n';
for entries in $(./export.bash); do export $entries; done;
"$#";
for entries in $(./export.bash); do variable=$(echo $entries|awk -F"=" '{print $1}'); unset $variable;
done
}
Source your .bashrc file and you can do like the above any time...
Anyhow back to the rest of it...
This has made it available globally then executed the script...
Simply echo it out and run export on the echo!
File export.bash
#!/bin/bash
echo "VAR=HELLO THERE"
Now within script or your console run:
export "$(./export.bash)"
Try:
echo $VAR
HELLO THERE
Multiple values so long as you know what you are expecting in another script using the above method:
File export.bash
#!/bin/bash
echo "VAR=HELLO THERE"
echo "VAR1=HI THERE"
File test-export.sh
#!/bin/bash
IFS=$'\n'
for entries in $(./export.bash); do
export $entries
done
echo "round 1"
echo $VAR
echo $VAR1
for entries in $(./export.bash); do
variable=$(echo $entries|awk -F"=" '{print $1}');
unset $variable
done
echo "round 2"
echo $VAR
echo $VAR1
Now the results
./test-export.sh
round 1
HELLO THERE
HI THERE
round 2
.
And the final final update to auto assign, read the VARIABLES:
./test-export.sh
Round 0 - Export out then find variable name -
Set current variable to the variable exported then echo its value
$VAR has value of HELLO THERE
$VAR1 has value of HI THERE
round 1 - we know what was exported and we will echo out known variables
HELLO THERE
HI THERE
Round 2 - We will just return the variable names and unset them
round 3 - Now we get nothing back
The script:
File test-export.sh
#!/bin/bash
IFS=$'\n'
echo "Round 0 - Export out then find variable name - "
echo "Set current variable to the variable exported then echo its value"
for entries in $(./export.bash); do
variable=$(echo $entries|awk -F"=" '{print $1}');
export $entries
eval current_variable=\$$variable
echo "\$$variable has value of $current_variable"
done
echo "round 1 - we know what was exported and we will echo out known variables"
echo $VAR
echo $VAR1
echo "Round 2 - We will just return the variable names and unset them "
for entries in $(./export.bash); do
variable=$(echo $entries|awk -F"=" '{print $1}');
unset $variable
done
echo "round 3 - Now we get nothing back"
echo $VAR
echo $VAR1
Execute
set -o allexport
Any variables you source from a file after this will be exported in your shell.
source conf-file
When you're done execute. This will disable allexport mode.
set +o allexport
I found an interesting and neat way to export environment variables from a file:
In file env.vars:
foo=test
Test script:
eval `cat env.vars`
echo $foo # => test
sh -c 'echo $foo' # =>
export eval `cat env.vars`
echo $foo # => test
sh -c 'echo $foo' # => test
# a better one. "--" stops processing options,
# key=value list given as parameters
export -- `cat env.vars`
echo $foo # => test
sh -c 'echo $foo' # => test
Another workaround that, depends on the case, it could be useful: creating another bash script that inherits the exported variable. It is a particular case of Keith Thompson's answer, will all of those drawbacks.
File export.bash:
# !/bin/bash
export VAR="HELLO, VARIABLE"
bash
Now:
./export.bash
echo $VAR
The answer is no, but for me I did the following
The script:
myExport
#! \bin\bash
export $1
An alias in my .bashrc file:
alias myExport='source myExport'
Still you source it, but maybe in this way it is more useable and it is interesting for someone else.
Maybe you can add a function in ~/.zshrc or ~/.bashrc.
# set my env
[ -s ~/.env ] && export MYENV=`cat ~/.env`
function myenv() { [[ -s ~/.env ]] && echo $argv > ~/.env && export MYENV=$argv }
Because of the use of a variable outside, you can avoid the use of a script file.
Export environment variables using script file
Problem:
When you run a script, it executes in a child shell and returns back to the parent shell after execution. Exporting variables only works down the child shells, you can't export a child shell's variable back to the parent shell.
Solution:
From your script file invoke a child shell along with variables that you want to export, this will create a new child shell with your variables exported.
script.sh ->
bash -c 'export VAR=variable; exec bash'
: : CIPH3R
I don't think this can be done, but I found a workaround using alias. It will only work when you place your script in your scripts directory. Otherwise your alias will have an invalid name.
The only point to the workaround is to be able to have a function inside a file with the same name and not have to bother sourcing it before using it. Add the following code to file ~/.bashrc:
alias myFunction='unalias myFunction && . myFunction && myFunction "$#"'
You can now call myFunction without sourcing it first.
This workaround is somehow hinted to elsewhere, but maybe not that clearly:
In your script, after setting the variable, start a new shell, rather than return.
My use cases is that I have a number of terminals open and in some of them I want some values for some variables, while in others I want other values.
As using source may be harder to remember, a small advantage of this approach is when it takes a while to realize that you forgot to use source, and you have to start from scratch.
(For me it makes more sense to use source script, as the missing variables are noticed immediately.)
I had similar problem calling ssh-agent -s in a script called by option -e in rsync.
In the script eval $(ssh-agent -s) don't preserve the environment variables for the next call.
rsync -e 'source ssh-check-agent.sh -p 8022' does not work, so I made a workaround. In the script I saved the variables in a temporal file after call ssh-agent like:
echo "export SSH_AUTH_SOCK=$SSH_AUTH_SOCK;" > /tmp/ssh-check-agent.vars
echo "export SSH_AGENT_PID=$SSH_AGENT_PID;" >> /tmp/ssh-check-agent.vars
and after in the script that calls rsync (backup.sh) I call:
source /tmp/ssh-check-agent.vars
The problem is that script that calls rsync must be called by source (source backup.sh).
I know that is not the question (I use two times source), but I put here if someone has similar problem with rsync.
simple naive approach that works:
script 1:
echo "something" > /tmp/myvar
script 2:
myvar=$(cat /tmp/myvar)
If you want to set a variable for the calling shell there is a robust approach using c unix sockets.
The result will be tested like this:
$ ./a.out &
[1] 5363
$ ./b.out 123;a=`./b.out`;echo ${a}
123
[1]+ Done ./a.out
See a.c, b.c, and a.h from my github.

Exporting variables in bash script to sub-sessions [duplicate]

Suppose that I have this script:
export.bash:
#! /usr/bin/env bash
export VAR="HELLO, VARIABLE"
When I execute the script and try to access to the $VAR, I don't get any value!
echo $VAR
Is there a way to access the $VAR by just executing export.bash without sourcing it?
Is there any way to access to the $VAR by just executing export.bash without sourcing it ?
Quick answer: No.
But there are several possible workarounds.
The most obvious one, which you've already mentioned, is to use source or . to execute the script in the context of the calling shell:
$ cat set-vars1.sh
export FOO=BAR
$ . set-vars1.sh
$ echo $FOO
BAR
Another way is to have the script, rather than setting an environment variable, print commands that will set the environment variable:
$ cat set-vars2.sh
#!/bin/bash
echo export FOO=BAR
$ eval "$(./set-vars2.sh)"
$ echo "$FOO"
BAR
A third approach is to have a script that sets your environment variable(s) internally and then invokes a specified command with that environment:
$ cat set-vars3.sh
#!/bin/bash
export FOO=BAR
exec "$#"
$ ./set-vars3.sh printenv | grep FOO
FOO=BAR
This last approach can be quite useful, though it's inconvenient for interactive use since it doesn't give you the settings in your current shell (with all the other settings and history you've built up).
In order to export out the VAR variable first, the most logical and seemly working way is to source the variable:
. ./export.bash
or
source ./export.bash
Now when echoing from the main shell, it works:
echo $VAR
HELLO, VARIABLE
We will now reset VAR:
export VAR=""
echo $VAR
Now we will execute a script to source the variable then unset it:
./test-export.sh
HELLO, VARIABLE
--
.
The code: file test-export.sh
#!/bin/bash
# Source env variable
source ./export.bash
# echo out the variable in test script
echo $VAR
# unset the variable
unset VAR
# echo a few dotted lines
echo "---"
# now return VAR which is blank
echo $VAR
Here is one way:
Please note: The exports are limited to the script that execute the exports in your main console - so as far as a cron job I would add it like the console like below... for the command part still questionable: here is how you would run in from your shell:
On your command prompt (so long as the export.bash file has multiple echo values)
IFS=$'\n'; for entries in $(./export.bash); do export $entries; done; ./v1.sh
HELLO THERE
HI THERE
File cat v1.sh
#!/bin/bash
echo $VAR
echo $VAR1
Now so long as this is for your usage - you could make the variables available for your scripts at any time by doing a Bash alias like this:
myvars ./v1.sh
HELLO THERE
HI THERE
echo $VAR
.
Add this to your .bashrc file:
function myvars() {
IFS=$'\n';
for entries in $(./export.bash); do export $entries; done;
"$#";
for entries in $(./export.bash); do variable=$(echo $entries|awk -F"=" '{print $1}'); unset $variable;
done
}
Source your .bashrc file and you can do like the above any time...
Anyhow back to the rest of it...
This has made it available globally then executed the script...
Simply echo it out and run export on the echo!
File export.bash
#!/bin/bash
echo "VAR=HELLO THERE"
Now within script or your console run:
export "$(./export.bash)"
Try:
echo $VAR
HELLO THERE
Multiple values so long as you know what you are expecting in another script using the above method:
File export.bash
#!/bin/bash
echo "VAR=HELLO THERE"
echo "VAR1=HI THERE"
File test-export.sh
#!/bin/bash
IFS=$'\n'
for entries in $(./export.bash); do
export $entries
done
echo "round 1"
echo $VAR
echo $VAR1
for entries in $(./export.bash); do
variable=$(echo $entries|awk -F"=" '{print $1}');
unset $variable
done
echo "round 2"
echo $VAR
echo $VAR1
Now the results
./test-export.sh
round 1
HELLO THERE
HI THERE
round 2
.
And the final final update to auto assign, read the VARIABLES:
./test-export.sh
Round 0 - Export out then find variable name -
Set current variable to the variable exported then echo its value
$VAR has value of HELLO THERE
$VAR1 has value of HI THERE
round 1 - we know what was exported and we will echo out known variables
HELLO THERE
HI THERE
Round 2 - We will just return the variable names and unset them
round 3 - Now we get nothing back
The script:
File test-export.sh
#!/bin/bash
IFS=$'\n'
echo "Round 0 - Export out then find variable name - "
echo "Set current variable to the variable exported then echo its value"
for entries in $(./export.bash); do
variable=$(echo $entries|awk -F"=" '{print $1}');
export $entries
eval current_variable=\$$variable
echo "\$$variable has value of $current_variable"
done
echo "round 1 - we know what was exported and we will echo out known variables"
echo $VAR
echo $VAR1
echo "Round 2 - We will just return the variable names and unset them "
for entries in $(./export.bash); do
variable=$(echo $entries|awk -F"=" '{print $1}');
unset $variable
done
echo "round 3 - Now we get nothing back"
echo $VAR
echo $VAR1
Execute
set -o allexport
Any variables you source from a file after this will be exported in your shell.
source conf-file
When you're done execute. This will disable allexport mode.
set +o allexport
I found an interesting and neat way to export environment variables from a file:
In file env.vars:
foo=test
Test script:
eval `cat env.vars`
echo $foo # => test
sh -c 'echo $foo' # =>
export eval `cat env.vars`
echo $foo # => test
sh -c 'echo $foo' # => test
# a better one. "--" stops processing options,
# key=value list given as parameters
export -- `cat env.vars`
echo $foo # => test
sh -c 'echo $foo' # => test
Another workaround that, depends on the case, it could be useful: creating another bash script that inherits the exported variable. It is a particular case of Keith Thompson's answer, will all of those drawbacks.
File export.bash:
# !/bin/bash
export VAR="HELLO, VARIABLE"
bash
Now:
./export.bash
echo $VAR
The answer is no, but for me I did the following
The script:
myExport
#! \bin\bash
export $1
An alias in my .bashrc file:
alias myExport='source myExport'
Still you source it, but maybe in this way it is more useable and it is interesting for someone else.
Maybe you can add a function in ~/.zshrc or ~/.bashrc.
# set my env
[ -s ~/.env ] && export MYENV=`cat ~/.env`
function myenv() { [[ -s ~/.env ]] && echo $argv > ~/.env && export MYENV=$argv }
Because of the use of a variable outside, you can avoid the use of a script file.
Export environment variables using script file
Problem:
When you run a script, it executes in a child shell and returns back to the parent shell after execution. Exporting variables only works down the child shells, you can't export a child shell's variable back to the parent shell.
Solution:
From your script file invoke a child shell along with variables that you want to export, this will create a new child shell with your variables exported.
script.sh ->
bash -c 'export VAR=variable; exec bash'
: : CIPH3R
I don't think this can be done, but I found a workaround using alias. It will only work when you place your script in your scripts directory. Otherwise your alias will have an invalid name.
The only point to the workaround is to be able to have a function inside a file with the same name and not have to bother sourcing it before using it. Add the following code to file ~/.bashrc:
alias myFunction='unalias myFunction && . myFunction && myFunction "$#"'
You can now call myFunction without sourcing it first.
This workaround is somehow hinted to elsewhere, but maybe not that clearly:
In your script, after setting the variable, start a new shell, rather than return.
My use cases is that I have a number of terminals open and in some of them I want some values for some variables, while in others I want other values.
As using source may be harder to remember, a small advantage of this approach is when it takes a while to realize that you forgot to use source, and you have to start from scratch.
(For me it makes more sense to use source script, as the missing variables are noticed immediately.)
I had similar problem calling ssh-agent -s in a script called by option -e in rsync.
In the script eval $(ssh-agent -s) don't preserve the environment variables for the next call.
rsync -e 'source ssh-check-agent.sh -p 8022' does not work, so I made a workaround. In the script I saved the variables in a temporal file after call ssh-agent like:
echo "export SSH_AUTH_SOCK=$SSH_AUTH_SOCK;" > /tmp/ssh-check-agent.vars
echo "export SSH_AGENT_PID=$SSH_AGENT_PID;" >> /tmp/ssh-check-agent.vars
and after in the script that calls rsync (backup.sh) I call:
source /tmp/ssh-check-agent.vars
The problem is that script that calls rsync must be called by source (source backup.sh).
I know that is not the question (I use two times source), but I put here if someone has similar problem with rsync.
simple naive approach that works:
script 1:
echo "something" > /tmp/myvar
script 2:
myvar=$(cat /tmp/myvar)
If you want to set a variable for the calling shell there is a robust approach using c unix sockets.
The result will be tested like this:
$ ./a.out &
[1] 5363
$ ./b.out 123;a=`./b.out`;echo ${a}
123
[1]+ Done ./a.out
See a.c, b.c, and a.h from my github.

Resources