subst

subst , a built-in Tcl command, substitutes variables commands, and backslash sequences in a string.

Synopsis

subst ?-nobackslashes? ?-nocommands? ?-novariables? string

Documentation

official manpage

Description

subst returns the given string with all variables, commands, and backslash sequences substituted. It does not interpret the string as a script, so quotes and braces don't have any effect. For example, in

subst {one two {[lindex {three four five} 1]}}

the result is

one two {four}

-nobackslashes, -nocommands, and novariables, respectively inhibit the corresponding substitutions.

subst and string map are handy for text-processing applications like SGML and XML transformations. Where in Perl, "right-hand-side" variables with regular expression substitution are used, in Tcl subst is used to substitute in the result of a regular expression match.

Examples

Simple example of using subst with XML/HTML.

set html   {<html><head>$title</head></html>}
set title  {Hello, World!}
set output [subst -nocommands $html] ;# -> <html><head>Hello, World!</head></html>

Another alternative would be to use XPath.

Generating Scripts and Lists

When using subst to generate a word in a script list should be used to quote the word:

set value {Hello, World}
set script [subst {
    puts [list $value]
}]
eval $script

The same is true when generating a list:

set item1 {some thing}
set item3 {three different things}
set list [subst {
    {a list item}
    $item3
    [list $item1]
    {another list item}
}]
lindex $list 4 ;# -> {some thing}

Discussion

RS most often uses subst for expanding Unicode characters: cross-platform, in mostly 8-bit environments, it is most robust to output characters in the \u.... notation. Such snippets can be pasted into a text widget and visualized by

subst [$t get 1.0 end]

Substitution and Evaluation

Although -nobackslashes, -nocommands, and -novariables, inhibit substitutions by subst itself, the interpreter that does the evaluation necessary for a substitution is not affected by these options. This means, for example, that even when -nocommands is given, command occurs in the following example:

set var {code inclusion perverse $tcl_platform(os[puts OUCH!])}
puts [subst -nocommands $var] 
==> OUCH!

In the following example, even though -novariable is given, variable substitution is performed:

set var hello
subst -novariables {[lindex $var]}

In the following example, even though -nobackslashes is given, backslash substitution is performed:

% subst -nobackslashes {$tcl_platform(threade\x64)\x64}
1\x64

reference: Eric Hassold, fr.comp.lang.tcl, 2008-12-30

reference: Tcl bug 536838

See also double substitution.

History

What changed in Tcl 8.4.0 with regards to how subst treats break and continue during command substitution?

See Tcl Bug 536831 , Tcl Feature Request 684982 , and the changes in the tests subst-10.*.

Without checking every byte, I think the incompatible changes are limited to those uses of subst that attempt command substitution on a string that is not a syntactically valid Tcl script -- arguably something no script should be doing anyway.

Enhancement Suggestion: Hook for Variable Expansion

jcw 2004-05-03: It would be useful to extend subst so it lets one catch variable accesses, and perhaps even command executions. What I mean is that when you subst text with "... $var ..." then sometimes it is useful to be able to intercept the expansion, by turning it into a call such as myhandler var for example, the result of which then gets used as substitution. The same (perhaps less important) might apply to ... [cmd ...] ... expansions.

This makes it simpler to implement tiny languages which also use $var and $var(item) as access mechanisms, but to things which are not necessarily stored in Tcl variables/arrays.

Would it be an idea to extend subst so it optionally passes each of its substitutions to a command? Could be a "-command ..." option, or simply the presence of more args.

DGP Am I missing something? Aren't you asking for variable and command traces, which exist?

D'oh! I'm missing that in this case you want to set a trace on a whole set of variables/commands whose names you do not know. OK, something to think about...

Anyhow, I think that's the right way to address the issue generally... add more types of traces that can be used everywhere. I'd be shy about diverging the implementation of subst from the implementation of the substitution portion of normal script evaluation.

jcw: Yes, that's exactly the scenario. subst on a string to expand names which are not known up front. Looks like there is no way to catch this right now. Perhaps some new "unknown traces" (or whatever terminology) would indeed be better. The key is to intercept between the parse for var/cmd expansions and the lookup for existing ones.

Parallel to double quoting

AMG: Am I correct in my understanding that:

[subst {anything at all}]

is always equivalent to:

"anything at all"

for absolutely any value of "anything at all"?

It occurred to me that if this is indeed the case, then maybe this equivalence could be the reason why backslash-newline-whitespace inside braces is replaced with a single space, in the interest of mirroring the way double quotes work. But then I experimented and found that subst internally will do this replacement and does not need the Tcl interpreter to preprocess its input in this way.

PYK: Could you elaborate on what you mean by "internally will do this replacement"?

AMG: subst internally replaces backslash-newline-whitespace with a single space. It's as simple as that. Here's a demonstration:

% subst abc\\\n\ \ def
abc def

PYK 2020-11-10: The statement of equivalence is not true:

subst {"} ;# -> the double quote character
lindex """ ;# -> error:  extra characters after close-quote

See also

eval
regsub
string map
an extension to subst
Template and Macro processing

Page Authors

Joe English
Lars H
pyk