LinuxQuestions.org
Support LQ: Use code LQ3 and save $3 on Domain Registration
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices



Reply
 
Search this Thread
Old 06-25-2013, 10:13 AM   #1
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,523

Rep: Reputation: 332Reputation: 332Reputation: 332Reputation: 332
Bash: Checking existence of environment variable using a string


I have a pretty good idea how to check for the existence of an environment variable, however I am having issues referencing the variable's value.

My script is something like:
Code:
#!/usr/bin/env bash

env_vars=( $(cat file.env) )

for var in $(env_vars[@]); do

        env | grep $var

        if [ $? -eq 0 ]; then
            echo $var found
        else
            echo $var not found
        fi
done
file.env contains single-line entries representing the names of the environment variable(s) I want to check. For example:
Code:
LD_LIBRARY_PATH
CLASSPATH
The questions regarding the script above are:

1. How can I be assured that "env | grep $var" returns an exact match, and not another similarly named environment variable (e.g. CLASSPATH vs. MYCLASSPATH vs. CLASSPATH_FOO)?

2. How can I display the current setting of the environment variable if it is found to exist?

Lastly, if it is not too much trouble to ask, how would I develop similar code but for Windows (ie. batch script)?
 
Old 06-25-2013, 11:04 AM   #2
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 1,948

Rep: Reputation: 524Reputation: 524Reputation: 524Reputation: 524Reputation: 524Reputation: 524
untested:
Code:
#!/bin/bash

env_vars=( $(cat file.env) )

for var in ${env_vars[@]}; do
    # echo "$var"
    # echo "${!var}"
    if [ "${!var-x}" = "x" -a "${!var-y}" = "y" ]; then
        printf '$%s not found\n' "$var"
    else
        printf 'found: $%s=%s\n' "$var" "${!var}"
    fi
done
 
1 members found this post helpful.
Old 06-25-2013, 11:15 AM   #3
grail
Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 7,698

Rep: Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988
Unless you wish to use the env_vars array later, I see no point in creating it first, just read the file. Generally I would recommend against reading with for, however, if you are
certain the file contains complete single strings on each line, I would probably go with:
Code:
#!/bin/bash

for var in $(< file.env)
do

    if [[ -n ${!var} ]]
    then
        echo "found $var = ${!var}"
    else
        echo "$var not found"
    fi
done
 
1 members found this post helpful.
Old 06-25-2013, 11:32 AM   #4
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,523

Original Poster
Rep: Reputation: 332Reputation: 332Reputation: 332Reputation: 332
NevemTeve & Grail -- Thanks for your replies. I was unaware of the ${!var} feature of bash.

My next step is to see if I can translate your suggestions into batch script.
 
Old 06-25-2013, 05:35 PM   #5
mina86
Member
 
Registered: Aug 2008
Distribution: Slackware
Posts: 414

Rep: Reputation: 173Reputation: 173
Note that -n will check whether variable is set to a non-empty value, which is not the same as if it is set. If you are interested in whether variable is set (with possibly empty value) or not, you should use:
Code:
if [ x${!var+set} = xset ]; then
    echo "found: $var=${!var}"
else
    echo "not fonud: $var"
fi
POSIX way would be to use eval (but you might want to sanitise $var first):
Code:
eval "[ x\${$var+set} = xset ]"

Last edited by mina86; 06-25-2013 at 05:37 PM.
 
Old 06-25-2013, 06:26 PM   #6
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,523

Original Poster
Rep: Reputation: 332Reputation: 332Reputation: 332Reputation: 332
mina86 -

I ended up using the -z option (since it seems to suit my needs), along with the critical hints from NevemTeve and Grail. My script, which is larger than the example below, merely is being used to indicate to the end-user whether an environment variable is set or not. If it is set, then I also display its value. Here's an example of what my script looks like:
Code:
#!/usr/bin/env bash

for var in $(< file.env); do
    if [ -z ${!var} ]; then
        echo variable $var is not set
    else
        echo variable $var is set to ${!var}
    fi
done
 
Old 06-25-2013, 06:52 PM   #7
mina86
Member
 
Registered: Aug 2008
Distribution: Slackware
Posts: 414

Rep: Reputation: 173Reputation: 173
Oh, that's actually invalid. You need to quote the variables:
Code:
for var in $(< file.env); do
    if [ -z "${!var}" ]; then
        echo "variable $var is not set or empty"
    else
        echo "variable $var is set to ${!var}"
    fi
done
 
Old 06-25-2013, 06:58 PM   #8
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,523

Original Poster
Rep: Reputation: 332Reputation: 332Reputation: 332Reputation: 332
Quote:
Originally Posted by mina86 View Post
Oh, that's actually invalid. You need to quote the variables:
Can you please explain the rationale for this? End-users will not be inserting "garbage" into the files, nor have I ever seen an environment variable with a white-space in it.
 
Old 06-26-2013, 05:02 AM   #9
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 1,948

Rep: Reputation: 524Reputation: 524Reputation: 524Reputation: 524Reputation: 524Reputation: 524
Script-writers (every programmer, actually) should make a habit of being paranoid with data coming from external sources (keyboard, network, files, environment variables etc)...
 
Old 06-26-2013, 08:52 AM   #10
mina86
Member
 
Registered: Aug 2008
Distribution: Slackware
Posts: 414

Rep: Reputation: 173Reputation: 173
Quote:
Originally Posted by dwhitney67 View Post
Can you please explain the rationale for this? End-users will not be inserting "garbage" into the files, nor have I ever seen an environment variable with a white-space in it.
You'd be surprised by what end users put into configuration files… Also, maybe in your case only a good citizens will use your script, but it's good to get into habit of assuming that all data coming into your programs may be created by malicious user, especially since it may simply be an user error or something you haven't anticipated but is a legitimate use. The fact that you have never seen an environment variable with a white-space means nothing (and white-space is the least of your concerns in this case).

Some ways to fool or otherwise abuse your script are:
Code:
$ cat a.sh
var=$1
if [ -z ${!var} ]; then
    echo variable $var is not set
else
    echo variable $var is set to ${!var}
fi
$ foo='!= bar' sh a.sh foo
variable foo is not set
$ time foo='/*/*/*/*' sh a.sh foo
^C

real	0m10.878s
user	0m0.060s
sys	0m0.124s
# yeah, 10 seconds was all the patience I had for that command, so I interrupted it
$ time sh a.sh '/*/*/*/*/*'                                                          ZRH:14:51 MTV:05:51 PIT:08:51
^C

real	0m6.896s
user	0m0.064s
sys	0m0.072s
# I had even less patience for this one
And I wasn't even trying things like foo='`rm -rf "$HOME"`', which I'm not 100% sure would work, but if you don't sanitise your input data, the danger is there.

Last edited by mina86; 06-26-2013 at 09:47 AM. Reason: typo
 
1 members found this post helpful.
Old 06-26-2013, 09:15 AM   #11
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,523

Original Poster
Rep: Reputation: 332Reputation: 332Reputation: 332Reputation: 332
Quote:
Originally Posted by mina86 View Post
You'd be surprised...
Thank you for the insight into how to exploit my script. I will make corrections to it immediately.
 
Old 06-28-2013, 07:11 AM   #12
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Debian sid + kde 3.5 & 4.4
Posts: 6,823

Rep: Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950
As shown, if the variable is set in the environment, then you can just test for its existence directly. Or there's also the built-in declare option you can use instead of env. This might be easiest, if the exact format of the output isn't particularly important.

And if you're using bash v4+, I suggest reading the file directly into an array fist with mapfile.

Code:
#!/usr/bin/env bash

mapfile -t env_vars <file.env

for var in "${env_vars[@]}"; do

    declare -p "$var"

done
If you don't have mapfile, then be sure to use a while+read loop, not a for loop.


Incidentally, bash from v4.2 also has a new -v test. You can check whether the variable name exists directly, without having to use an indirect reference.

Code:
if [[ -v $var ]]; then
    echo "variable $var is set to ${!var}"
    ...
 
Old 06-28-2013, 07:37 AM   #13
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,523

Original Poster
Rep: Reputation: 332Reputation: 332Reputation: 332Reputation: 332
Thanks for the tips. One of the systems that my script runs on, has Bash 3.00.16. The system is a Solaris 10 Sparc.
 
Old 06-28-2013, 12:38 PM   #14
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 1,948

Rep: Reputation: 524Reputation: 524Reputation: 524Reputation: 524Reputation: 524Reputation: 524
Reading a whole file into memory is a very good way to eat up every bit of RAM.
 
Old 06-28-2013, 01:27 PM   #15
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Debian sid + kde 3.5 & 4.4
Posts: 6,823

Rep: Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950
But that depends on how big the file is, of course, and the amount of RAM you have available. I don't think that you're going to get lists of environment variables in the multi-gigabyte range.

Do remember to unset the array when you're done if you're worried about the data sitting there in memory, though.

Anyway, the traditional way to load an array from a file, or to process it directly, for that matter, is like this:
Code:
while IFS='' read -r line || [[ -n $line ]]; do
    array+=( "$line" )
done <infile.txt
 
  


Reply

Tags
bash, batch, regexp


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Setting An Environment Variable In Bash? carlosinfl Red Hat 7 02-24-2012 07:55 AM
[SOLVED] Bash concatenating string to variable abercrombieande Programming 4 01-19-2011 08:04 AM
[SOLVED] Checking the existence of env variable mahmoodn Linux - General 8 06-12-2010 10:51 AM
how to unset environment variable in bash suneel Linux - Newbie 7 09-14-2009 11:17 AM
bash: checking if a variable is a number (need regular expression help) anonguy9 Linux - Newbie 6 03-29-2009 03:37 AM


All times are GMT -5. The time now is 08:43 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration