From: Ahmad on
Hi,

I'm reading a configuration file passed to my tcl script.

This configuration file, could contain paths to certain files using
environment variables: for example:

file1_path $var1/$var2/${var3}/file.ext

My script is parsing the config file, splitting each line to get key
and value (path) of entries.

But passing this path directly to tcl nees to be first converted to
$env(...)

I tried to use regsub to change all occurrences of cases like this,
using:

set a {var1/$var2/${var3}/nonVar/file.ext}
set b [split $a '/']
regsub -all {$([^/]+)} \$env(\1) $b

But I don't know why it's always returning $evn( )

What is wrong in my expression?

Is there any easier way to interpret shell env vars?

Thanks,
Ahmad
From: Ahmad on
I'm afraid I cannot understand.

$var1, $var2, ... are random env vars names parsed from a config
file.

I need to interpret their corresponding value into my tcl script.

Is that what do you mean?

Thanks,
Ahmad


On Aug 5, 2:38 pm, "Gerald W. Lester" <Gerald.Les...(a)KnG-
Consulting.net> wrote:
> Ahmad wrote:
> > Hi,
>
> > I'm reading a configuration file passed to my tcl script.
>
> > This configuration file, could contain paths to certain files using
> > environment variables: for example:
>
> > file1_path $var1/$var2/${var3}/file.ext
>
> > My script is parsing the config file, splitting each line to get key
> > and value (path) of entries.
>
> > But passing this path directly to tcl nees to be first converted to
> > $env(...)
>
> > I tried to use regsub to change all occurrences of cases like this,
> > using:
>
> > set a {var1/$var2/${var3}/nonVar/file.ext}
> > set b [split $a '/']
> > regsub -all {$([^/]+)} \$env(\1) $b
>
> > But I don't know why it's always returning $evn( )
>
> > What is wrong in my expression?
>
> > Is there any easier way to interpret shell env vars?
>
> Yes, depends on how safe you want to be.
>
> Least safe:
>
> Define a procedure which takes the file string (lets say file) which:
> 1) defines a local variable (e.g. var1) for each env var (e.g. ::env(var1))
> 2) return a [subst -nocommand -nobackslash $file]
>
> Most safe:
> Create a safe interp with all commands hidden except subst.
> Define global variables (e.g. var1) for each env var (e.g. ::env(var1))
> evaluate [list subst -nocommand -nobackslash $file] in the safe interp
>
> --
> +------------------------------------------------------------------------+
> | Gerald W. Lester, President, KNG Consulting LLC                        |
> | Email: Gerald.Les...(a)kng-consulting.net                                |
> +------------------------------------------------------------------------+

From: Donald Arseneau on
On Aug 5, 1:09 pm, Ahmad <ahmad.abdulgh...(a)gmail.com> wrote:

> This configuration file, could contain paths to certain files using
> environment variables: for example:
>
> file1_path $var1/$var2/${var3}/file.ext
>
> But passing this path directly to tcl nees to be first converted to
> $env(...)

How about copying environment variables into Tcl variables?

proc substEnv { string } {
set string [string map { {::} {} } $string]
foreach {ev val} [array get ::env] {
set $ev $val
}
return [subst -nocommand -nobackslashes $string]
}

Donald Arseneau
From: Ahmad on
Thank you all,

You taught me a lot indeed!

Although the regsub way worked with me, I'm curious to know how
"substEnv" function works.

I'm trying to use: substEnv varName and it returns the same name. I
tried with $varName, then it gave me error.

Regards,
Ahmad

On Aug 5, 4:26 pm, Andreas Leitgeb <a...(a)gamma.logic.tuwien.ac.at>
wrote:
> Ahmad <ahmad.abdulgh...(a)gmail.com> wrote:
> > set a {var1/$var2/${var3}/nonVar/file.ext}
> > set b [split $a '/']
> > regsub -all {$([^/]+)} \$env(\1) $b
> > But I don't know why it's always returning $evn( )
>
> There's a whole bunch of little mistakes... ;)
>  -) first of all, you got the order of arguments for regsub
>       wrong - you mixed up the input string with the
>       substitute-pattern.
>  -) the search-pattern doesn't escape the $, so it will never
>       match anything (an unescaped dollar matches the end of string,
>       so nothing could follow it for a match)
>       You likely want the pattern {\$\{?([^/\}]+)\}?} instead, which
>       also discard eventual braces from braced variables.
>  -) you split for '/', but single quotes aren't special in tcl, so
>       you split by the literal 3-chars-string: quote,slash,quote,
>       which isn't found in $a, so you effectively get $a back, with
>       another level of list quoting, just as if you had written:
>       set b [list $a]
>  -) If you fixed the split command to split by slashes alone, then the
>       regexp-pattern would match everything after the first dollar, as
>       there wouldn't be any slashes left.  Better leave the split out
>       completely, and apply the regsub on $a instead.
>  -) finally, the \1 in \$env(\1) get's prematurely substed. regsub doesn't
>       see the backslash-one sequence, but a character with code 1 (^A)
>       Use {$env(\1)} instead.
>
> regsub -all {\$\{?([^/\}]+)\}?} $a {$env(\1)}
>
> Others have posted solutions boiling down to copying the environment
> variables into local variables of a procedure or even a new interpreter.
> That's perhaps the simpler approach, though not necessarily the better.
> And it takes a bit more than the naive approach, in order not to let the
> iteration variables interfere with the variables created, if e.g. there
> was a real envvar named "en" or "val".

From: Andreas Leitgeb on
Ahmad <ahmad.abdulghany(a)gmail.com> wrote:
> Although the regsub way worked with me, I'm curious to know how
> "substEnv" function works.
> I'm trying to use: substEnv varName and it returns the same name. I
> tried with $varName, then it gave me error.

I'm not sure, what substEnv you mean, so I assume you made a procedure
for the stuff previously explained.

Now, let's see what happens...
substEnv varName
you pass in the string "varName", which contains no dollar-chars, so
substEnv hasn't got anything to do with it, and returns it unchanged.

substEnv $varName
before substEnv is called, it's argument is parsed, and the interpreter
tries to substitute $varName for the value stored in a variable "varName".
As you say, it throws an error, it's possible that you meant "varName" to
be an actual environment-variable, and no local variable of that name exists.

substEnv {$varName}
will pass the literal string (dollar and varName) to the function, and
the function will replace it by $env(varName), or perhaps even replace
it with the actual environment-var's value.

If you post your exact definition of substVar, we can help further, e.g.
spot mistakes in substVar that also might cause errors.