Chapter 7. Commands

Table of Contents
How to Issue Commands
Rexx and Batch Files
Using Variables to Build Commands
Using Quotation Marks
ADDRESS Instruction
Using Return Codes from Commands
Subcommand Processing
Trapping Command Errors

From a Rexx program you can pass commands to Windows and Unix/Linux shells or to applications designed to work with Rexx. When used to run operating system commands, Rexx becomes a powerful substitute for the Windows Batch Facility or Unix shell scripts. You can use variables, control structures, mathematics, and parsing, and the full object oriented features of Rexx.

Applications that are designed to work with Rexx are often referred to as scriptable applications. To work with Rexx, a scriptable application registers a command environment with Rexx. An environment serves as a kind of workspace shared between Rexx and the application that accepts application commands issued from your Rexx programs.

For example, many editors provide a command prompt or dialog box from which you can issue commands to set margins or add lines. If the editor is scriptable from Rexx, you can issue the same editor commands from a Rexx program. These Rexx programs are referred to as macros.

When an application runs a Rexx macro, Rexx directs commands to the application's environment. The application processes the command, and returns a status indicator as a return code.

The Rexx ADDRESS instruction allows you select which named command environment commands get directed to. There is always at least one active command environment, and all Rexx programs start with a default environment selected. For programs launched from a command shell, an operating-specific command handler is the normal default. Applications such as an editor can choose to make their own command environment the default.

How to Issue Commands

Rexx makes it easy to issue commands. The basic rule is that whatever Rexx cannot process directly gets passed to the current command environment. You can:

Rexx processes your program one clause at a time. It examines each clause to determine if it is:

If the clause is none of the above, Rexx evaluates the entire clause as an expression and passes the resulting string to the current command environment.

If the string is a valid valid command for that environment, the command handler will process it as if you had entered it at the command prompt.

The following example shows a Rexx clause that uses the Windows DIR command to display a list of files in the current directory.

/* display current directory */
say "DIR command using Rexx"
dir

The clause dir is not a Rexx instruction or a label, so Rexx evaluates it and passes the resulting string to Windows. Windows recognizes the string DIR as one of its commands and processes it.

Letting Rexx evaluate the command as an expression might cause problems, however. Try adding a path to the DIR command in the above program (such as, dir c:\config.sys). The Windows command in this case is an incorrect Rexx expression. The program ends with an error.

A safer way to issue commands is by enclosing the command in quotes, which makes the command a literal string. Rexx does not evaluate the contents of strings, so the string is passed to Windows as-is. Here is an example using the PATH command:

/* display current path      */
say "PATH command using Rexx"
"path"

The following example, DP.CMD, shows a program using the DIR and PATH commands. The PAUSE command is added to wait for the user to press a key before issuing the next instruction or command. Borders are added too.

/* DP.CMD -- Issue DIR and PATH commands to Windows */

say "="~copies(40)    /* display line of equal   */
                      /* signs (=) for a border  */

"dir"                 /* display listing of      */
                      /* the current directory   */

"pause"               /* pauses processing and   */
                      /* tells user to "Press    */
                      /* any key to continue."   */

say "="~copies(40)    /* display line of =       */
"path"                /* display the current     */
                      /* PATH setting            */

When you specify the following:

[C:\]rexx dp

a possible output would be:

========================================

The volume label in drive C is WIN.
Directory of C:\EXAMPLES

.            <DIR>     10-16-94  12:43p
..           <DIR>     10-16-94  12:43p
EX4_1    CMD     nnnn  10-16-94   1:08p
DEMO     TXT      117  10-16-94   1:10p
4 File(s)   12163072 bytes free
Press any key when ready . . .

========================================
PATH=C:\WINDOWS
[C:\]

Note: Usually, when executing a host command addressed to the Windows or Unix/Linux command shell, a new process is created in the system command handler to execute the command. Changes in a child process environment do not change the parent process environment. Therefore, any change in the environment, such as a directory change, made by a host command executed in a child process would not be reflected in the process running the Rexx program.

The interpreter attempts to mitigate this to some extent by executing some host commands in the process running the Rexx program, rather than in a child process. This is done so that changes to the environment made by executing the host command are visible in the process running the Rexx program.

This is only done when the host command line is simple. That is, the command line must contain a single command, without redirection and without pipe. On Windows this applies to the CD and SET commands. On Unix-like systems, including Linux, this applies to cd, set, unset and export. Rather than remembering the rules, it may be easier to avoid a potential problem by using the built in directory() or value() functions rather than issuing a host command for cd, set, etc.

Some examples for Windows:

'cd c:\tmp'               /* executed in Rexx program process */
'cd "c:\R&D (secret)"'    /* executed in Rexx program process */
'cd c:\windows && dir c:' /* executed in child process (2 commands) */
'd:'                      /* executed in Rexx program process */
'set myvar=my value'      /* executed in Rexx program process */

Some examples for Unix:

'cd'                      /* executed in Rexx program process: go to $HOME directory */
'cd ~/"R&D (secret)"'     /* executed in Rexx program process: go to $HOME/R&D (secret) */
'cd ~/"R&D \"secret\""'   /* executed in Rexx program process: go to $HOME/R&D "secret" */
'cd ~john'                /* executed in Rexx program process: go to John's home directory */
'cd /tmp && pwd'          /* executed in child process (2 commands) */
'set myvar=my value'      /* executed in Rexx program process */
'export myvar=my value'   /* executed in Rexx program process */
'unset myvar'             /* executed in Rexx program process */