Set Env Var and Access From Bash Script - linux

This is probably a really stupid question, but how do I set an Environment Variable in Bash, then access it in a shell script?
kkeiper#machine:/home/kkeiper $ export APIKEY="adsf"
In bash script
#!/bin/bash
echo $APIKEY; # prints a blank line
echo $(env | grep APIKEY); # wouldn't return APIKEY even if it did work, but this also prints a blank string

What you show should work! It does for me:
$ export APIKEY="asfw"
$ cat script.sh
#!/bin/bash
echo $APIKEY
env | grep APIKEY
$ bash -x script.sh
+ echo asfw
asfw
+ env
+ grep APIKEY
APIKEY=asfw
$ sudo bash script.sh
Password:
$
Note that you don't need the semicolons or the echo $(...) notation in the script — but they don't do any damage either.
(Tested Mac OS X 10.9 Mavericks, Bash 3.2.51. However, I don't expect it to matter. Only true Bourne shells don't support the export VAR=value notation — and you'll have to look hard to find a shell with that limitation these days; Solaris /bin/sh, perhaps.)
Example with sudo added after question in comments. Yes, sudo unsets stray environment variables such as APIKEY.
More notes on sudo:
$ env | wc -l
24
$ env | grep APIKEY
APIKEY=asfw
$ cat script.sh
#!/bin/bash
echo $APIKEY
env | grep APIKEY
env | wc -l
$ bash script.sh
asfw
APIKEY=asfw
23
$ sudo bash script.sh
18
$
One day, I'll investigate the what and the why for the difference between 24 and 23 environment variables without sudo being involved, but clearly sudo eliminated a number of variables (5 or 6, including APIKEY specifically).
How to ensure that environment variables are preserved?
If you know which ones need to be preserved, then:
The sudo man page says:
-E The -E (preserve environment) option will override the env_reset option
in sudoers(5)). It is only available when either the matching command
has the SETENV tag or the setenv option is set in sudoers(5).
You can arrange to relay the environment variables to the commands environment:
$ sudo -E bash script.sh
Password:
asfw
APIKEY=asfw
26
$ sudo bash -c "APIKEY='$APIKEY' bash script.sh"
asfw
APIKEY=asfw
SUDO_COMMAND=/bin/bash -c APIKEY='asfw' bash script.sh
19
$
The appearance of SUDO_COMMAND in the environment is interesting.
(Note that the bash script.sh notation is only needed because I've not made script.sh executable. If it was executable, I could type either script.sh or ./script.sh depending on whether it is in a directory on my $PATH or not.)

Related

bash command working from terminal but not from script [duplicate]

a.sh
#! /bin/sh
export x=/usr/local
we can do source ./a in command-line. But I need to do the export through shell script.
b.sh
#! /bin/sh
. ~/a.sh
no error... but $x in command-line will show nothing. So it didn't get export.
Any idea how to make it work?
a.sh
#! /bin/sh
export x=/usr/local
-----------
admin#client: ./a.sh
admin#client: echo $x
admin#client: <insert ....>
You can put export statements in a shell script and then use the 'source' command to execute it in the current process:
source a.sh
You can't do an export through a shell script, because a shell script runs in a child shell process, and only children of the child shell would inherit the export.
The reason for using source is to have the current shell execute the commands
It's very common to place export commands in a file such as .bashrc which a bash will source on startup (or similar files for other shells)
Another idea is that you could create a shell script which generates an export command as it's output:
shell$ cat > script.sh
#!/bin/sh
echo export foo=bar
^D
chmod u+x script.sh
And then have the current shell execute that output
shell$ `./script.sh`
shell$ echo $foo
bar
shell$ /bin/sh
$ echo $foo
bar
(note above that the invocation of the script is surrounded by backticks, to cause the shell to execute the output of the script)
Answering my own question here, using the answers above: if I have more than one related variable to export which use the same value as part of each export, I can do this:
#!/bin/bash
export TEST_EXPORT=$1
export TEST_EXPORT_2=$1_2
export TEST_EXPORT_TWICE=$1_$1
and save as e.g. ~/Desktop/TEST_EXPORTING
and finally $chmod +x ~/Desktop/TEST_EXPORTING
--
After that, running it with source ~/Desktop/TEST_EXPORTING bob
and then checking with export | grep bob should show what you expect.
Exporting a variable into the environment only makes that variable visible to child processes. There is no way for a child to modify the environment of its parent.
Another way you can do it (to steal/expound upon the idea above), is to put the script in ~/bin and make sure ~/bin is in your PATH. Then you can access your variable globally. This is just an example I use to compile my Go source code which needs the GOPATH variable to point to the current directory (assuming you're in the directory you need to compile your source code from):
From ~/bin/GOPATH:
#!/bin/bash
echo declare -x GOPATH=$(pwd)
Then you just do:
#> $(GOPATH)
So you can now use $(GOPATH) from within your other scripts too, such as custom build scripts which can automatically invoke this variable and declare it on the fly thanks to $(pwd).
script1.sh
shell_ppid=$PPID
shell_epoch=$(grep se.exec_start "/proc/${shell_ppid}/sched" | sed 's/[[:space:]]//g' | cut -f2 -d: | cut -f1 -d.)
now_epoch=$(($(date +%s%N)/1000000))
shell_start=$(( (now_epoch - shell_epoch)/1000 ))
env_md5=$(md5sum <<<"${shell_ppid}-${shell_start}"| sed 's/[[:space:]]//g' | cut -f1 -d-)
tmp_dir="/tmp/ToD-env-${env_md5}"
mkdir -p "${tmp_dir}"
ENV_PROPS="${tmp_dir}/.env"
echo "FOO=BAR" > "${ENV_PROPS}"
script2.sh
shell_ppid=$PPID
shell_epoch=$(grep se.exec_start "/proc/${shell_ppid}/sched" | sed 's/[[:space:]]//g' | cut -f2 -d: | cut -f1 -d.)
now_epoch=$(($(date +%s%N)/1000000))
shell_start=$(( (now_epoch - shell_epoch)/1000 ))
env_md5=$(md5sum <<<"${shell_ppid}-${shell_start}"| sed 's/[[:space:]]//g' | cut -f1 -d-)
tmp_dir="/tmp/ToD-env-${env_md5}"
mkdir -p "${tmp_dir}"
ENV_PROPS="${tmp_dir}/.env"
source "${ENV_PROPS}"
echo $FOO
./script1.sh
./script2.sh
BAR
It persists for the scripts run in the same parent shell, and it prevents collisions.

Why are the results from terminal and bash script different? [duplicate]

This question already has answers here:
How to use aliases defined in .bashrc in other scripts?
(6 answers)
Closed 1 year ago.
USER#HOST:~:$ cat .bashrc
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
# User specific aliases and functions
alias sudo='sudo -i'
USER#HOST:~:$ cat tmp.sh
#!/bin/bash
sudo env | grep PATH
USER#HOST:~:$ ./tmp.sh
PATH=/usr/bin:/bin:/usr/sbin:/sbin
USER#HOST:~:$ sudo env | grep PATH
PATH=/usr/python-3.8.2-r2/bin:/usr/jdk64/jdk1.8.0_112/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/bin:/root/bin
I put an alias setting in my .bashrc file.
When I test it through a terminal, it's okay.
But it seems to work differently when done with a script.
What's the difference here, and how can I test this through script?
The alias does not apply to the script. You'll see the equivalent if you use command to bypass alias expansion in the shell:
$ command sudo env | grep PATH

Bash script tee command syntax issue

I want to echo the following line at the end of ~/.profile file using tee command:
export PATH="$HOME/.local/bin:$PATH"
To do this my bash script looks like this
#!/bin/bash
path_env="export PATH="$HOME/.local/bin:$PATH""
echo $path_env| sudo tee -a $HOME/.profile > /dev/null
But whenever I am executing the script it is also executing $PATH and $HOME value and inserts that in ~./profile file which I do not want. I only want the exact line to be passed by the bash script instead of replacing $PATH and $HOME with its own values.
I only want the exact line to be passed by the bash script instead of replacing $PATH and $HOME with its own values.
Och, right, so do not expand it. Quoting.
path_env='export PATH="$HOME/.local/bin:$PATH"'
echo "$path_env" | sudo tee -a "$HOME/.profile" > /dev/null

How environment variables can be read from a file when going into a login shell with here-string and using the sudo command?

I am trying to write a small script that aims to login to a remote server, load environment variables and print one of them. (In the actual script, instead of an echo, the parameters that are read are to be used. For the sake of simplicity here I am using just echo.)
The structure of the script and the commands that I tried are as follows but unfortunately none succeeds:
ssh -i lightsail.pem ubuntu#production <<< '
sudo echo $TEST_PARAMETER
sudo sh -c "~/Environment/environment-variables.sh && echo $TEST_PARAMETER"
sudo bash -c "~/Environment/environment-variables.sh && echo $TEST_PARAMETER"
sudo bash -c "source ~/Environment/environment-variables.sh && echo $TEST_PARAMETER"
sudo bash <<< "source ~/Environment/environment-variables.sh && echo $TEST_PARAMETER"
';
How environment variables can be read from a file when going into a login shell with here-string and using the sudo command?
If your environment variable is set for ubuntu and not root you will need to use sudo -E
-E Indicates to the security policy that the user wishes to preserve their existing environment variables

Option -l of exec shell command

Could you please clarify on the use of -l option of exec shell command. I didn't notice any difference when I ran exec ls | cat and exec -l ls | cat.
The -l option of exec adds a - at the beginning of the name of your command. For example:
exec -l diff | head
-diff: missing operand after '-diff'
-diff: Try '-diff --help' for more information.
Note the - everywhere before diff.
The point of all this? If you have a - before a command to start a shell it will act as a login shell. From man bash:
A login shell is one whose first character of argument zero is a -, or one started with the --login option.
Now, man exec states that:
If the -l option is supplied, the shell places a dash at the beginning of the zeroth argument passed to command. This is
what login(1) does.
So exec -l bash will run bash as a login shell. To test this, we can use the fact that a login bash executes the file ~/.bash_profile, so:
$ cat ~/.bash_profile
#!/bin/sh
printf "I am a login shell!\n"
If I start a login bash, the command printf "I am a login shell!\n" will be executed. Now to test with exec:
$ exec bash
$
Nothing is displayed, we are on a non-login shell.
$ exec -l bash
I am a login shell!
$
Here we have a login shell.

Resources