symbol_substitution

This is an old revision of the document!


Symbol Substitution

As explained here, the term “symbol” is nothing more than an old-fashioned name for “variable” – a DCL symbol is simply a DCL variable, just as Linux/Unix shells like bash have shell variables.

One of the most important things that you can do with script variables (DCL symbols) is to substitute a variable's value into another string of characters. This is called string substitution – in more modern scripting languages like Ruby, Python and Perl, this is also called string interpolation; you will see both terms in ordinary (technical, programming) conversation.

DCL's string substitution lets you:

  1. Use the value of a variable (symbol) in or on a command line
  2. Substitute (interpolate, or insert) the value of a variable into a quoted-string of text
  3. Substitute (interpolate, or insert) the value of a DCL Lexical Function into a quoted-string of text

You'll find these techniques and uses of string substitution primarily in DCL command files, or scripts, which exploit many of the same programming techniques as those more modern scripting languages.

String Substitution Examples

Let's first take a simple example of #1 (list above) – A command file (script) to implement a “fancy(er) SHOW DEVICE command” (the non-empty-comment lines, the lines with executable code, are line-numbered):

$ ! FANCYSHOW.COM -- implements a fanci(er) SHOW DEVICE command      !  1
$ !
$ ! P1 - Device (or logical) name to show                            !  3
$ !
$ IF ( P1 .EQS. "" )                                                 !  5
$ THEN READ sys$command /PROMPT="Show what? " /END_OF_FILE=Done dev  !  6
$ ELSE dev = P1                                                      !  7
$ ENDIF                                                              !  8
$ dev = F$GETDVI( dev, "DEVNAM" )                                    !  9
$ !
$ SHOW DEVICE /FULL 'dev'                                            ! 11
$ IF ( F$GETDVI( dev, "SHDW_MASTER" ) )                              ! 12
$ THEN WRITE sys$output "Disk ''dev' is a Shadow-Set Volume"         ! 13
$      SHOW SHADOW 'dev'                                             ! 14
$ ENDIF                                                              ! 15
$ SHOW DEVICE 'dev'                                                  ! 16
$ !
$Done:                                                               ! 18
$ EXIT 1                                                             ! 19
$ !

Lines 1 through 4 are just internal documentation, and inform us that the DCL parameter symbol P1 is used to collect the name of the device to show from the command line; if the user does not specify that device name on the command line (tested at Line 5), s/he is prompted for it at Line 6; if P1 is specified on the command line, its value is simply copied to the variable (symbol) dev at Line 7.

In either case, that variable dev is recomputed (overwritten) by assigning the result of the lexical function F$GETDVI at Line 8 (an example of #3 from the list above); the function's argument “DEVNAM” makes it look up the proper physical device name for whatever is specified as its first input argument (again by the dev variable's initial value). And Line 12 re-uses that lexical function to test (determine) whether or not that physical device is a Shadow-Set Volume.

The actual examples of string substitution (#2 from the list above) happen at Lines 11, 13, 14 and 16

Lines 11, 14 and 16 are of the form (with variations):

$ SHOW DEVICE 'dev'
              ^^^^^

Focus on the symbol/variable name 'dev' as surrounded by one single-quote mark (', also called an apostrophe) on either end (as underlined by the ^^^^^ carets). That notation – 'dev' – means “substitute the value, the contents, of the named variable as a string of characters right here, completely replacing the 'dev' with that string of text.”

Assume that the contents of variable dev is exactly the string of characters “DSA2:”. After that string substitution is done, what the DCL command interpreter “sees” and processes is exactly this:

$ SHOW DEVICE DSA2:
              ^^^^

That string substitution operation resulted in replacing the notation 'dev' with the value or contents of that variable dev, namely the characters DSA2: (for this example – your mileage will vary).

But next look carefully at Line 13:

$ ... WRITE sys$output "Disk ''dev' is a Shadow-Set Volume"
                             ^^^^^^

Here, you see a slightly different notation: Instead of 'dev', with a single single-quote mark (') at each end of the variable's name, we see two leading single-quote marks at the beginning, and one single-quote mark following that variable name – Why?

This is still valid notation for string substitution, but here the substitution is done within a double-quoted () literal string of characters:

  "... ''dev' ..."

So, after string substitution, and still assuming that the value of variable dev is still the string of characters ”DSA2:“, the WRITE command is processed as:

$ ... WRITE sys$output "Disk DSA2: is a Shadow-Set Volume"
                             ^^^^^

,,,and happily outputs this line of text, with the string substitution, to the user's terminal display/screen:

Disk DSA2: is a Shadow-Set Volume

String Substitution Punctuation and Notation

It is vitally important that you see – be able to read and recognize – the difference between single-quote marks (') (also called a “tick mark” or ”tick“ or “apostrophe”) and double-quote marks () (sometimes called just a “quote”). Novice DCL programmers who fail to make these important distinctions, both when they read DCL scripts and when they write/code them, get quickly into deep problems and errors.

So, from the above examples, you can derive two rules:

  1. If you are string-substituting directly onto the command line, anywhere not within a double-quoted, literal text string, put a single-quote mark ' on either/both ends of the variable's name; surround the variable's name with single-quote marks.
  2. If you are string-substituting within a literal, double-quoted string of characters, put two single-quote marks in front of the variable's name, and one single-quote mark at its end.

Yes, rule 2's form – spoken as “… <tick><tick>variable_name<tick> …” – seems a bit strange, arbitrary and even picky… But the original DCL software engineers built it this way, and that's just the way it is.

Producing Quotes in Quotes

What if you want to produce literal double-quote marks to be printed in a string of text? – like this:

This is "double-quoted-text".

…or surround some text with single quotes? – like this:

This is 'singled-quoted-text'.

These are pretty common use-cases – See the wiki article Literal Quotes in DCL Strings for full details.

Command File Parameters P1 thru P8

For the purposes of string substitution (interpolation), the command line parameters P1, P2, P3, P4, P5, P6, P7 and P8 are simply DCL local variables within command files, and therefore everything you've learned above applies to these parameter variables for string substitution/replacement. For more info on this, see the wiki article Command File Parameters.

Another command file example may suffice to demonstrate this:

$ ! COM_FILE_PARAMETERS.COM -- demonstrate command-line parameters
$ !                            as used by the command file...
$ !
$ wso = "WRITE sys$output"  ! alias command, short-hand
$ !
$ wso "The value of P1 is: ""''p1'"""
$ wso "The value of P2 is: ""''p2'"""
$ wso "The value of P3 is: ""''p3'"""
$ wso "The value of P4 is: ""''p4'"""
$ wso "The value of P5 is: ""''p5'"""
$ wso "The value of P6 is: ""''p6'"""
$ wso "The value of P7 is: ""''p7'"""
$ wso "The value of P8 is: ""''p8'"""
$ !
$ EXIT 1
$ !

…and some example command-line invocations (uses):

$ @com_file_parameters This is a test

…produces these output lines:

The value of P1 is: "THIS"
The value of P2 is: "IS"
The value of P3 is: "A"
The value of P4 is: "TEST"
The value of P5 is: ""
The value of P6 is: ""
The value of P7 is: ""
The value of P8 is: ""

Only four individual “words” were used for this demo, so these became the values of P1, P2, P3, and P4 (all forced to UPPERCASE because the words/values were not double-quoted on the command line), leaving P5P8 as “empty strings”. Compare that to:

$ @com_file_parameters "This is a test"
The value of P1 is: "This is a test"
The value of P2 is: ""
The value of P3 is: ""
The value of P4 is: ""
The value of P5 is: ""
The value of P6 is: ""
The value of P7 is: ""
The value of P8 is: ""

…and to:

$ @com_file_parameters "Value1" "" "" "" "Value5" "" "" "Value8-last"
The value of P1 is: "Value1"
The value of P2 is: ""
The value of P3 is: ""
The value of P4 is: ""
The value of P5 is: "Value5"
The value of P6 is: ""
The value of P7 is: ""
The value of P8 is: "Value8-last"

Copy this simple com-file to your own system and play with it – experiment with different combinations of com-line parameters and see what happens!

That Tricky Little &

You might have noticed that the tick-varname-tick and “tick-tick-varname-tick” tricks are not the only ways to get DCL to do string substitution for the contents of a variable. Or you might stumble onto a piece of DCL command-file code that looks something like this:

$ P3 = "IMPORTANT_FILE.DATA"
$ ...
$ ! later...
$ COUNT = 3
$ TYPE &P'COUNT'
$ ...

…and you immediately wonder: What the heck is that &P'COUNT' construction used as the TYPE command's parameter? The short answer is that the ampersand (&) is a delayed string substitution operator, and its substitution is done only when any and all other tick-mark string substitutions are done (for the construct).

Buried deep in the official VMS documentation set (specifically, see the OpenVMS User's Manual (Order Number: AA–PV5JF–TK, June 2002)“, Chapter 12, “Defining Symbols, Commands and Expressions,” Section 12.12,2 “Symbol Substitution Operators,” pp 12-26 through 12-31, for all the details) is information on how to use the seldom-encountered ampersand (&) string substitution operator.

Honestly, you'll very seldom, if ever, need to use the &-operator for string substitution in DCL – it is used (and useful) for only a rarely encountered use-case. Here are the rules and use, just in case you ever run into it when reading someone else's com-file, or if you need it yourself:

  • DCL processes single-quoted symbol (ticked variable) names from left to right in a command line, replacing any such tick-varname-tick and “tick-tick-varname-tick” instances with the value of each symbol as encountered. This is called forced substitution (or requested substitution).
  • Symbols preceded by single apostrophes (not in double-quotes: tick-varname-tick) are translated iteratively; symbols preceded by double apostrophes (as in double-quotes “tick-tick-varname-tick”) are not (substitution inside of double-quotes is once-only, when encountered).
  • DCL performs iterative substitutions in multiple phases or passes (for a given construct like &P'COUNT'): First, any and all single-tick-mark substitutions (tick-varname-tick) are done – yes, an early(er) string substitution could result in a subst-value which itself is single-tick-mark surrounded, hence iterative substitution (very rarely done, and confusing!). Then, finally, the &-substitution is done on whatever symbols (variable) name results from the earlier substitution(s). Confused yet? Take fresh courage: this is a rarely used feature of DCL!

The upshot of this is simply that the &-substitution operator delays its own substitution until any and all earlier tick-mark-substitutions have been done. So, looking again at the previous example:

    $ TYPE &P'COUNT'
    --becomes-->  $ TYPE &P3
    --becomes-->  $ TYPE IMPORTANT_FILE.DATA
    ...and the contents of
       the IMPORTANT_FILE.DATA file
       are displayed.
symbol_substitution.1542739011.txt.gz · Last modified: 2018/11/20 18:36 by lricker