$ZF(-100) permits an InterSystems IRIS process to invoke an executable program or a command of the host operating system. For example, here are two sample Windows® commands for listing and copying files.
set listStatus = $zf(-100,"/SHELL","dir","/q")
set copyStatus = $zf(-100,"/SHELL","copy","myfile.txt","c:\InterSystems")
$ZF(-100) executes the program or command specified in program as a spawned child process from the current console. It allows you to invoke a program or command either synchronously or asynchronously, with or without invoking the operating system shell. $ZF(-100) provides similar functionality to $ZF(-1) and $ZF(-2). Its use is preferable to $ZF(-1) or $ZF(-2), which are both deprecated functions.
You can use a local array and indirection to specify a variable number of args, as shown in the following UNIX® example:
SET status = $ZF(-100,"/ASYNC", "gcc",.args)
$ZF(-100) sets $ZCHILD to the PID of the started program.
You can execute $ZF(-100) as an argument of the DO command. DO $ZF(-100) differs in two ways from calling $ZF(-100) as a function:
DO ignores the returned integer status code.
You can append an argument postconditional expression to $ZF(-100). For example, DO:x $ZF(-100,"", "gcc",.args):y $ZF(-100,"/ASYNC", "gcc",.args):z specifies three postconditionals. It does not execute the DO command when x=0, it does not execute “gcc” synchronously when y=0, and does not execute “gcc” asynchronously when z=0. A postconditional expression prevents execution, but does not prevent argument evaluation.
How $ZF(-100) executes depends on the flags string values:
/ASYNC: Execute program asynchronously; do not wait for it to complete. The default is to execute synchronously.
If /ASYNC is not specified and /STDIN, /STDOUT, or /STDERR is not specified, InterSystems IRIS attempts to use the operating systems’ current descriptors or standard handles for these files.
/ENV=environmentvars: Specifies environment variables to be set in the new process. There are two ways to specify the values:
Explicitly. The format is /ENV=(name:value) There can be multiple name:value pairs separated by a comma.
Via a multidimensional array where the subscripts are the environment variable names and the values are the values for the environment variables.
Because the entire flags argument is a string, the name and value are always treated as strings, not variable names. If these contain characters that would interfere with parsing the rest of the string, such as colon or comma, they must be enclosed in quotes, which must be doubled because they are within the flags string.
This example will run the command with variable MYNAME equal to "Tom" and MYARG equal to "comma,":
This example produces the same result as the previous one:
The examples show two environment variables but there can be any number. The explicit list must be enclosed in parentheses.
/SHELL: Execute program using a shell. The default is to not use a shell.
/STDIN=filename: I/O redirection input file.
/STDOUT=filename: I/O redirection standard data output file. If filename does not exist, the system will create it. If filename exists, /STDOUT=filename will overwrite existing data; /STDOUT+=filename will append to existing data.
/STDERR=filename: I/O redirection standard error output file. If filename does not exist, the system will create it. If filename exists, /STDERR=filename will overwrite existing error log data; /STDERR+=filename will append to existing error log data. If you specify the same file for /STDOUT and /STDERR, both types of data will be written to that file.
/LOGCMD: log the resulting command line in messages.log. Because sometimes it can be hard to get the arguments for complex commands right, this keyword flag allows developers to check if the arguments passed to the command are being correctly formed (especially with regard to quoting). The log facility does not add any quotes or other delimiters. The messages.log entry is truncated at 1000 characters.
/NOQUOTE: inhibit automatic quoting of commands, command arguments, or filenames. By default, $ZF(-100) provides automatic quoting, and escaping of spaces in paths that is appropriate for most user-supplied values. When needed, you can override this default by specifying /NOQUOTE; the user is then responsible for providing appropriate quotes. See Quoting User-Specified Values.
To specify $ZF(-100) with no keyword flags, specify the empty string for this argument:
SET status = $ZF(-100,"", "ls", "-l")
I/O redirection for /STDIN=filename, /STDOUT=filename, and /STDERR=filename follow UNIX® conventions. On both UNIX and Windows systems:
/STDIN=filename: The file with that filename is linked to the stdin file handle given to the process that executes the specified cmd string.
/STDOUT=filename: If a file with that filename does not already exist, it is created. For an existing file, /STDOUT=filename truncates the file to zero size; /STDOUT+=filename appends to the existing file data. This file is linked to the stdout handle given to the process that executes the specified cmd string. This creates a new file containing the stdout output of the spawned command.
/STDERR=filename: If a file with that filename does not already exist, it is created. For an existing file, /STDERR=filename truncates the file to zero size; /STDERR+=filename appends to the existing file data. This file is linked to the stderr handle given to the process that executes the specified cmd string. This creates a new file containing the stderr output of the spawned command.
If /STDIN, /STDOUT, or /STDERR is not specified:
If /ASYNC is specified, the null device is used in place of the unspecified file(s). A handle that references the null device is given to the process that executes the specified cmd string as the unspecified file’s handle.
If /ASYNC is not specified, the handle used by the InterSystems IRIS job executing the $ZF(-100) function is copied and is given to the process that executes the specified cmd string as the unspecified file’s handle.
On a Windows system you should never omit both the /ASYNC and /STDIN flags.
If /STDIN, /STDOUT, or /STDERR specifies a file that cannot be created or opened, the null device is used in place of the file.
If /STDOUT=filename and /STDERR=filename (or /STDOUT+=filename and /STDERR+=filename) specify the same filename, the specified file is only opened or created once. The resulting file handle is duplicated and supplied as both the stdout and stderr file handles given to the process that executes the specified cmd string. $ZF(-100) generates an <ILLEGAL VALUE> error if you specify the same file for /STDOUT and /STDERR, and one is specified +=filename and the other is specified =filename.
Quoting User-Specified Values
By default,$ZF(-100) provides automatic quoting of a command and the arguments to the command. It automatically handles blank spaces if your executable is in a directory with spaces in the name or a command argument specifies a file for output that contains a space. $ZF(-100) supplies delimiting double quote characters as needed. This behavior is shown in the following example:
DO $ZF(-100,"/LOGCMD","c:\sdelete64.exe","-nobanner","c:\dir1\nested directory\deleteme\")
This logs the following to messages.log; $ZF(-100) quotes the final argument to escape the space in the file path:
06/14/18-14:25:05:988 (3788) 0 $ZF(-100) cmd=c:\sdelete64.exe -nobanner "c:\dir1\nested directory\deleteme\"
06/14/18-14:25:06:020 (3788) 0 $ZF(-100) ret=0
If the automatic quoting provided does not correctly escape what you want escaped, use the /NOQUOTE flag, which suppresses automatic quoting, and use your own quoting, as needed. If a specified value contains a / character or a blank space, the value must be quoted using doubled double quotes. This is shown in the following example:
DO $ZF(-100,"/NOQUOTE /LOGCMD","c:\sdelete64.exe","""-nobanner""","""c:\dir2\""")
This logs the following to messages.log:
06/15/18-09:27:38:619 (3788) 0 $ZF(-100) cmd=c:\sdelete64.exe "-nobanner" "c:\dir2\"
06/15/18-09:27:38:650 (3788) 0 $ZF(-100) ret=0
The behavior differs on UNIX® and Windows systems:
On a Windows system, if /SHELL is not specified, a command line is created and passed. In this case, some arguments may need to be quoted.
On any system, when /SHELL is specified, a command line is created and passed. In this case some arguments may need to be quoted.
Double quotes found within a command or command argument are escaped as applicable for the operating system.
Return Status Codes
$ZF(-100) returns the following status codes:
0 if the child process was successfully launched asynchronously (with /ASYNC flag). Status of program execution unknown.
-1 if the child process could not be forked.
An integer if launched synchronously (no /ASYNC flag). This integer exit status code value is determined by the application called on the host operating system. Commonly it is a positive integer, but some applications may return a negative integer. For example, for most Windows command syntax errors, $ZF(-100) returns 1.
$ZF(-100) with the /SHELL argument launches the default operating system shell. For further details, see Running Programs or System Commands with $ZF(-100).
If a pathname supplied in program contains a space character, pathname handling is platform-dependent. Windows and UNIX® permit space characters in pathnames, but the entire pathname containing spaces must be enclosed in an additional set of double quote (") characters. This is in accordance with the Windows cmd /c statement. For further details, specify cmd /? at the Windows command prompt.
You can use the NormalizeFilenameWithSpaces()Opens in a new tab method of the %Library.FileOpens in a new tab class to handle spaces in pathnames as appropriate for the host platform.
$ZF(-100) requires the %System_Callout:U privilege. See Adding the %System_Callout:USE Privilege for details.
If $ZF(-100) is unable to spawn a process, it generates a <FUNCTION> error.
$ZF(-100) generates a <NOTOPEN> error if:
The /STDIN=filename, /STDOUT=filename, or /STDERR=filename could not be opened.
The specified program could not be started.
The error is logged in SYSLOG. The operating system error number and message are available from the %SYSTEM.Process.OSError()Opens in a new tab method.
An OS command audit record is added to the audit log for each $ZF(-100) call. This record includes information such as the following:
Command: /Users/myname/IRIS/jlc/bin/clmanager 4002