20

For some shell sessions I want to be able to print a warning flag if a shell variable is not set and exported.

It is fairly simple to do something like this to print "Error" in the prompt if SET_ME is unset or null.

test_var () { test -z "$1" && echo Error; }
PS1='$(test_var "$SET_ME") \$ '

However this fails to flag if I set SET_ME without exporting it, which is an error that I want to be able to detect. Short of something like $(bash -c 'test -z "$SET_ME" && echo Error;') or grepping the output of export, is there a simple check that I can do to test whether SET_ME has been exported?

A non-POSIX, bash-only solution is completely acceptable.

11

Use the declare command and the regular expression matching operator:

test_var () {
    # $1 - name of a shell variable
    var=$1
    [[ -z "${!var}" ]] && echo Error
    [[ $(declare -p $1)  =~ ^declare\ -[aAilrtu]*x[aAilrtu]*\  ]] || echo Error
}
  • I think that this is what I'm looking for. In theory, the re might need to be more flexible, e.g. if I had a read-only exported variable, but in practice I never use other typeset attributes. – CB Bailey Jul 19 '12 at 13:36
  • Good point. I'll fix it for posterity. – chepner Jul 19 '12 at 13:40
  • It looks like attempting to quote the regular expression stops it working as a regular expression in bash >= 3.2. – CB Bailey Jul 19 '12 at 14:14
  • Also there's an inconsistency, -z "$1" assumes I'm passing the value of a variable to test_var (as I was) whereas declare -p expects its name. I came up with this test which takes the name of a shell variable: test_exported_notnull () { re='^declare -\w*x'; [[ -n $(eval echo \$$1) ]] && [[ $(declare -p "$1") =~ $re ]]; } . – CB Bailey Jul 19 '12 at 14:51
  • To avoid the eval, just add this first line: var=$1, then use [[ -z "${!var}" ]] && echo Error. – chepner Jul 19 '12 at 16:00
4

I'm aware the question is 3 years old, however one may find following solution simpler:

[ "$(bash -c 'echo ${variable}')" ]

answers, if the variable is exported and has non-empty value.

4

In Bash 4.4 or later, you can use the ${parameter@a} shell parameter expansion to get a list of attributes about a parameter, including if it is exported.

Here is a simple function demonstrating ${parameter@a}, that will tell you if a given variable is exported, given its name:

function is_exported {
    local name="$1"
    if [[ "${!name@a}" == *x* ]]; then
        echo "Yes - '$name' is exported."
    else
        echo "No - '$name' is not exported."
    fi
}

Example of use:

$ is_exported PATH
Yes - 'PATH' is exported.
$ foo=1 is_exported foo
Yes - 'abc' is exported.
$ bar=1; is_exported bar
No - 'abc' is not exported.
$ export baz=1; is_exported baz
Yes - 'baz' is exported.
$ export -n baz; is_exported baz
No - 'baz' is not exported.
$ declare -x qux=3; is_exported qux
Yes - 'qux' is exported.

How it works:

The format returned by ${parameter@a} is one character per attribute, with the meaning of each attribute character coming from the corresponding options from the declare command - in this case, we want to look for x - exported.

  • Best Answer if you are using Bash 4.4 or newer! – Andy Apr 26 at 14:53
3

You can use compgen with its -X option to determine if a variable is exported:

compgen -e -X "!$MAY_BE_EXPORTED_VARIABLE"

E.g.:

$ NOT_EXPORTED="xxx"
$ compgen -e -X '!SHELL'
SHELL
$ compgen -e -X '!NOT_EXPORTED'
$ echo $?
1
  • Best compatible answer! Over twice as slow as the ${parameter@a} solution, but far more compatible for bash 3.2 cases – Andy Apr 26 at 14:54
2

If I resign myself to having to use export and grep, the simplest test is probably something like this.

export | grep -Eq '^declare -x SET_ME='

or if I want non-null as well:

export | grep -Eq '^declare -x SET_ME=".+"'
1

The export command, given without parameters, gives a list of exported names in the current environment:

$ FOO1=test
$ FOO2=test
$ export | grep FOO
$ export FOO2
$ export | grep FOO
declare -x FOO2="test"

Some cutting and sed'ing gets rid of the fluff:

export | cut -d' ' -f 3- | sed s/=.*//

There's your list of exports, ready for further processing.

  • 1
    This does work but I was hoping for a lighter answer with fewer implied forks (hence "Short of [...] grepping the output of export") as my planned use is in my prompt. – CB Bailey Jul 19 '12 at 12:15
  • @CharlesBailey: I see. I came to this by searching the bash manpage for export, and this was the only thing I came up with. No help from the shell escapes either. The export is builtin anyway, but I doubt you can avoid the grep. – DevSolar Jul 19 '12 at 12:26
1

The simplest method I currently can think of:

[ bash -c ': ${v1?}' 2>/dev/null ]

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.