darrickc
darrickc

Reputation: 1932

Is there a way in csh to dynamically check environment variables?

I have a c application that calls out to a csh script with lots of information. I'd like to expand that in such a way that the csh script can loop through the environment variables. For example, the c application would set the following envs

COUNT=4
SOMETHING_1=HELLO
SOMETHING_2=WORLD
SOMETHING_3=WIDE
SOMETHING_4=WEB

And the csh script can loop through the SOMETHINGs and print out the envs based on the count env.

Is it possible to evaluate a programatically generated env?

I tried doing this to test the theory:

#!/bin/csh -f

foreach n ( 1 2 3 4 )
        eval "$SOMETHING"_"$n"
end

But that obviously didn't work.

Upvotes: 1

Views: 1993

Answers (2)

shellter
shellter

Reputation: 37298

All you're missing is a \ char, i.e.

#!/bin/csh -f

foreach n ( 1 2 3 4 )
        eval echo \$"SOMETHING"_"$n"
        # --------^--- here
end

I've added an echo here so that eval has something safe, but visible to do.

Change your shebang line to use debug/trace mode, i.e.

#!/bin/csh -fvx

and define

     SOMETHING=abc

and you'll see the two passes that the eval does, you'll (should) see where

 echo $SOMETHING_1
 echo "value of abc_1 =$abc_1 XXX"

but of course, you'll have to define a value for variable abc_1.

Finally, don't get to rely on using eval. Use it only as a last resort, and only where you have control over what strings will be evaled.

It would be very easy for a malcontent to pass in harmful code that will be executed by the eval.

(And sorry, I don't have a csh handy to test this so let me know if you have troubles).

Finally, read widely published articles that csh is not a great language for programming. Switch to bash or ksh at your earliest convenience. You won't regret it.

IHTH

Upvotes: 3

Keith Thompson
Keith Thompson

Reputation: 263547

If one of the variables is not set, your script will crash; referring to an undefined variable in csh/tcsh is an error. (This is unlike sh/bash, where $FOO by default expands to the empty string if the variable isn't set.)

If you can safely assume that all the relevant variables are set, then shellter's solution should be ok. If you want to do some error checking, read on.

The csh/tcsh syntax for testing whether a variable $VAR is defined or not is $?VAR. It evaluates to 0 or 1.

An example:

#!/bin/tcsh -f

setenv SOMETHING_1 foo
setenv SOMETHING_3 bar

foreach i (1 2 3 4 5)
    set is_set = `eval echo '$?SOMETHING_'$i`
    if ($is_set) then
        echo '$SOMETHING_'$i is set to `eval echo '$SOMETHING_'$i`
    else
        echo '$SOMETHING_'$i is not set
    endif
end

Output:

$SOMETHING_1 is set to foo
$SOMETHING_2 is not set
$SOMETHING_3 is set to bar
$SOMETHING_4 is not set
$SOMETHING_5 is not set

As shellter's answer mentions, eval is potentially unsafe unless you have complete control over what's passed to it. In this particular case that's not an issue.

Another possible solution might be to parse the output of printenv -- but that could run into problems if some environment variables have values with strange characters such as newlines.

Or you could write and invoke a small program in another language; for example C's getenv() or Perl's %ENV don't require the use of eval to determine whether an arbitrary environment variable is set or not, and are not vulnerable to values with strange characters.

I vaguely recall that in some old versions of csh, the $?VAR syntax worked only for shell variables, not for environment variables. It does work in tcsh and in more modern versions of csh.

Upvotes: 3

Related Questions