From: Gerald W. Lester on
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.Lester(a)kng-consulting.net |
+------------------------------------------------------------------------+
From: Andreas Leitgeb on
Ahmad <ahmad.abdulghany(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".