Looking for the existence of an ENV Variable - bash

So, I'm guessing this may be a bug, or maybe I've botched something up, I dunno...
I have a script that was always working but I've been tasked to make it work using the new WSL2. I've snipped out the first block of code as it's giving me issues right off the bat. As you'll see below, I'm simply trying to determine if a variable has been set or not. This works in my Linux VM and also in Cygwin, however, it doesn't work in WSL2. Here is the code:
#!/bin/bash
echo $test_var
set -e
if [ ! -d "$test_var" ]; then
echo Please set test_var.
exit
fi
When I run this in any of the working systems I get the output of the variable.
In WSL2 I get the output of the variable followed by Please set test_var. And it stops the script due to the set -e as it's supposed to do thinking the var isn't set.
Any help would be appreciated.
Thanks

If your intention is to check if a directory exists (whose name apparently needs to be set as an environment variable in $test_var), if that directory exists relative to the current directory where the script is executed, you want something like:
#!/bin/bash
echo "$test_var"
set -e
if [ ! -d "$test_var" ]; then
echo "cannot find directory $test_var"
exit
fi
Note that here I have only changed your message, and your problem might possibly be explained by the fact that you do not have such a directory under WSL2.
If, on the other hand, you want to check if some environment variable (whatever it represents) is set, you want the -z option, something like:
#!/bin/bash
echo "$test_var"
set -e
if [ -z "$test_var" ]; then
echo "Please set test_var."
exit
fi
Note the absence of your negation sign (!).

Related

Why can [ -x file ] be false even after chmod 777 file?

I'm an italian student trying to study bash. I have a question. I've to solve this following bash script
#!/bin/bash
echo hello
if [ -x "$namefile" ] ; then
echo "file $namefile exists"
else
echo " file $namefile doesn't exists"
fi
Reading your posts I understand that -x means if the file exists and is executable is true.
Now I have created a file with all permissions for all with chmod 777 file and I try to launch the script but the result is "File doesn't exists". Why?
This is a reverse engineering exercise and I can't modify the script.
If you don't want to modify your script, set the variable when calling the script:
namefile=myfile.txt ./sestoscr
(assuming that sestoscr is the name of the script you posted, and that the script has execute permission, and that myfile.txt is the name of the file you want to test using your script).
A more flexible solution would be to change the test in your script to
if [ -x "${namefile:=$1}" ] ; then
This still allows you to invoke the script via a change in environment (as outline above), but you also can call it using an explicit parameter,
./sestoscr myfile.txt
However, in this case I would give the positional parameter priority over the environment (because this is what most users would expect), and write it as:
namefile=${1:-$namefile}
if [ -x "$namefile" ]; ...
With this approach, if a parameter is supplied, it uses the parameter, and if none is supplied, it uses the environment variable namefile.

Creating a "First run" notification in bash?

What is the best way to make a "First run" notification in a bash script?
I tried putting export FIRSTRUN="no" first,
and later on put
`if [ -z "$FIRSTRUN" ]; then
echo "It seems that this may be your first time running this script.";
echo "Please ${GREEN}test whether the needed components are installed${RESET}.";
echo "";
fi`
but it simply does it on every time the script is run. If i put the export FIRSTRUN="no" after the if part, it never runs the if part of the code. So that doesn't work.
I am new at this so please help :D
You can't modify the parent shell state from within your script, so attempting to export a variable will not work.
You could use a config file to store a variable which determines whether the script has been run already:
#!/bin/bash
# load vars from config at the start of the script
if [[ -f ~/.your_script.conf ]]; then
. ~/.your_script.conf
fi
# check whether var has been set to determine first run
if [[ -z $has_run ]]; then
echo 'first run'
# set variable in config file for next time
echo 'has_run=1' >> ~/.your_script.conf
fi
Alternatively, if this is the only "config" you have, you could just create a file after the first run and check for its existence to determine whether the script has been run.
The first run of the script should leave behind some sort of permanent evidence that it has run; it can then look for that file on startup.
do_init () {
# initialize whatever needs initializing
touch ~/.alreadyran
}
if ! [ -f ~/.alreadyran ]; then
echo "First time running."
do_init
fi
If the initialization isn't per-user, it will need to leave the file in a more public place, such as somewhere under /var.

If Statement With Blank Variable

I can't get this to work correctly. If the wifissid is blank, it needs to display "Wireless: Not Connected". If the wifissid is not blank, it needs to display "Wireless: Connected To $wifissid"
wifissid=Test
if [ $wifissid = "*" ]; then
WirelessOutput=" Wireless: Connected To $wifissid"
else
WirelessOutput=" Wireless: Not Connected"
exit
fi
echo " $WirelessOutput"
Try this. The ! -z checks to see if $wifissid is not (!) empty/null (-z). Or use -n which basically is the same as ! -z. More details on these operators here:
#!/bin/bash
wifissid=Test
# if [ -n "$wifissid" ]; then
if [ ! -z "$wifissid" ]; then
WirelessOutput=" Wireless: Connected To $wifissid"
else
WirelessOutput=" Wireless: Not Connected"
fi
echo " $WirelessOutput"
exit
Also, I didn’t understand why you had an exit in the else statement since that would prevent the echo from ever happening. So I removed that and added it to the bottom of the script.
Additionally, I added #!/bin/bash to the top of the script because that is just something you should get in the habit of doing. It helps prevent issues such as if this script were running as a cron job, the default sh instead of bash would interpret the script & it would fail.
Might seem like small things, but it’s the little things that will drive you nuts if/when things don’t work out as expected.

Shell script to check whether the mounted path given in fstab/mtab is valid

I have mounted several windows machine in Linux machine through fstab.
Eg:
*//vmdevmachine/sharedfolder /var/lib/jenkins/Windows/ cifs
gid=users,file_mode=0664,dir_mode=0775,auto,username=user_name,password=password123*
I have few jobs to run, that are dependent on mounted machines like this.
My requirement: Before running the job I need (shell script) to check whether the mounted file/directory is valid/exist or not.
i.e from the above example, it need to check whether **//vmdevmachine/sharedfolder** exist or not.
Thanks,
-Rajiv
If the directory is mounted currently and does not have a link such as a symlink to it I generally use something like the below.
if [ ! -d "/var/lib/jenkins/Windows/" ]; then
exit $? # The script will exit with exit status from If statement.
fi
If the directory (-d) does not exist (!) then exit with the exit code from the if statement. If you are going to be doing multiple directories may want to put them in an array and iterate through them quick like so
files=( "/var/lib/jenkins/Windows/" "/var/lib/jenkins/Windows/2" "/var/lib/jenkins/Windows/3" )
for i in "${files[#]}"
do
if [ ! -d "$i" ]; then
exit $? # The script will exit with exit status from If statement.
fi
done
In the above for loop example $i will be the directory during each instance of the for loop. I hope this helps you out as I am still getting used to posting here.

How to write a bash script to set global environment variable?

Recently I wrote a script which sets an environment variable, take a look:
#!/bin/bash
echo "Pass a path:"
read path
echo $path
defaultPath=/home/$(whoami)/Desktop
if [ -n "$path" ]; then
export my_var=$path
else
echo "Path is empty! Exporting default path ..."
export my_var=$defaultPath
fi
echo "Exported path: $my_var"
It works just great but the problem is that my_var is available just locally, I mean in console window where I ran the script.
How to write a script which allow me to export global environment variable which can be seen everywhere?
Just run your shell script preceded by "." (dot space).
This causes the script to run the instructions in the original shell. Thus the variables still exist after the script finish
Ex:
cat setmyvar.sh
export myvar=exists
. ./setmyvar.sh
echo $myvar
exists
Each and every shell has its own environment. There's no Universal environment that will magically appear in all console windows. An environment variable created in one shell cannot be accessed in another shell.
It's even more restrictive. If one shell spawns a subshell, that subshell has access to the parent's environment variables, but if that subshell creates an environment variable, it's not accessible in the parent shell.
If all of your shells need access to the same set of variables, you can create a startup file that will set them for you. This is done in BASH via the $HOME/.bash_profile file (or through $HOME/.profile if $HOME/.bash_profile doesn't exist) or through $HOME/.bashrc. Other shells have their own set of startup files. One is used for logins, and one is used for shells spawned without logins (and, as with bash, a third for non-interactive shells). See the manpage to learn exactly what startup scripts are used and what order they're executed).
You can try using shared memory, but I believe that only works while processes are running, so even if you figured out a way to set a piece of shared memory, it would go away as soon as that command is finished. (I've rarely used shared memory except for named pipes). Otherwise, there's really no way to set an environment variable in one shell and have another shell automatically pick it up. You can try using named pipes or writing that environment variable to a file for other shells to pick it up.
Imagine the problems that could happen if someone could change the environment of one shell without my knowledge.
Actually I found an way to achieve this (which in my case was to use a bash script to set a number of security credentials)
I just call bash from inside the script and the spawned shell now has the export values
export API_USERNAME=abc
export API_PASSWORD=bbbb
bash
now calling the file using ~/.app-x-setup.sh will give me an interactive shell with those environment values setup
The following were extracted from 2nd paragraph from David W.'s answer: "If one shell spawns a subshell, that subshell has access to the parent's environment variables, but if that subshell creates an environment variable, it's not accessible in the parent shell."
In case a user need to let parent shell access your new environment variables, just issue the following command in parent shell:
source <your_subshell_script>
or using shortcut
. <your_subshell_script>
You got to add the variable in your .profile located in /home/$USER/.profile
Yo can do that with this command:
echo 'TEST="hi"' >> $HOME/.profile
Or by edit the file with emacs, for example.
If you want to set this variable for all users, you got to edit /etc/profile (root)
There is no global environment, really, in UNIX.
Each process has an environment, originally inherited from the parent, but it is local to the process after the initial creation.
You can only modify your own, unless you go digging around in the process using a debugger.
write it to a temporary file, lets say ~/.myglobalvar and read it from anywhere
echo "$myglobal" > ~/.myglobalvar
Environment variables are always "local" to process execution the export command allow to set environment variables for sub processes. You can look at .bashrc to set environment variables at the start of a bash shell. What you are trying to do seems not possible as a process cannot modify (or access ?) to environment variables of another process.
You can update the ~/.bashrc or ~/.bash_profile file which is used to initialize the environment.
Take a look at the loading behavior of your shell (explained in the manpage, usually referring to .XXXshrc or .profile). Some configuration files are loaded at login time of an interactive shell, some are loaded each time you run a shell. Placing your variable in the latter might result in the behavior you want, e.g. always having the variable set using that distinct shell (for example bash).
If you need to dynamically set and reference environment variables in shell scripts, there is a work around. Judge for yourself whether is worth doing, but here it is.
The strategy involves having a 'set' script which dynamically writes a 'load' script, which has code to set and export an environment variable. The 'load' script is then executed periodically by other scripts which need to reference the variable. BTW, the same strategy could be done by writing and reading a file instead of a variable.
Here's a quick example...
Set_Load_PROCESSING_SIGNAL.sh
#!/bin/bash
PROCESSING_SIGNAL_SCRIPT=./Load_PROCESSING_SIGNAL.sh
echo "#!/bin/bash" > $PROCESSING_SIGNAL_SCRIPT
echo "export PROCESSING_SIGNAL=$1" >> $PROCESSING_SIGNAL_SCRIPT
chmod ug+rwx $PROCESSING_SIGNAL_SCRIPT
Load_PROCESSING_SIGNAL.sh (this gets dynamically created when the above is run)
#!/bin/bash
export PROCESSING_SIGNAL=1
You can test this with
Test_PROCESSING_SIGNAL.sh
#!/bin/bash
PROCESSING_SIGNAL_SCRIPT=./Load_PROCESSING_SIGNAL.sh
N=1
LIM=100
while [ $N -le $LIM ]
do
# DO WHATEVER LOOP PROCESSING IS NEEDED
echo "N = $N"
sleep 5
N=$(( $N + 1 ))
# CHECK PROCESSING_SIGNAL
source $PROCESSING_SIGNAL_SCRIPT
if [[ $PROCESSING_SIGNAL -eq 0 ]]; then
# Write log info indicating that the signal to stop processing was detected
# Write out all relevent info
# Send an alert email of this too
# Then exit
echo "Detected PROCESSING_SIGNAL for all stop. Exiting..."
exit 1
fi
done
~/.bin/SOURCED/lazy script to save and load data as flat files for system.
[ ! -d ~/.megadata ] && mkdir ~/.megadata
function save_data {
[ -z "$1" -o -z "$2" ] && echo 'save_data [:id:] [:data:]' && return
local overwrite=${3-false}
[ "$overwrite" = 'true' ] && echo "$2" > ~/.megadata/$1 && return
[ ! -f ~/.megadata/$1 ] && echo "$2" > ~/.megadata/$1 || echo ID TAKEN set third param to true to overwrite
}
save_data computer engine
cat ~/.megadata/computer
save_data computer engine
save_data computer megaengine true
function get_data {
[ -z "$1" -o -f $1 ] && echo 'get_data [:id:]' && return
[ -f ~/.megadata/$1 ] && cat ~/.megadata/$1 || echo ID NOT FOUND
:
}
get_data computer
get_data computer
Maybe a little off topic, but when you really need it to set it temporarily to execute some script and ended up here looking for answers:
If you need to run a script with certain environment variables that you don't need to keep after execution you could do something like this:
#!/usr/bin/env sh
export XDEBUG_SESSION=$(hostname);echo "running with xdebug: $XDEBUG_SESSION";$#
In my example I just use XDEBUG_SESSION with a hostname, but you can use multiple variables. Keep them separated with a semi-colon. Execution as follows (assuming you called the script debug.sh and placed it in the same directory as your php script):
$ debug.sh php yourscript.php

Resources