Running Programs or System Commands with $ZF(-100)
The $ZF(-100) function permits an InterSystems IRIS® process to invoke an executable program or a command of the host operating system. This is the only $ZF function that can be used without a special Callout shared library (see “Creating an InterSystems Callout Library”). The following topics are discussed in this chapter:
Also see $ZF(-100) (ObjectScript) in the ObjectScript Reference.
$ZF(-100) replaces deprecated functions $ZF(-1) and $ZF(-2), and should be preferred in all cases.
$ZF(-100) provides functionality similar to that of a command line interface, allowing you to invoke an executable program or a command of the host operating system. The syntax of this function is:
status = $ZF(-100, keywords, command, arguments )
The first argument must be a literal -100. The other three arguments specify the following information:
keywords — a string containing keywords that specify various options. For example, the string "/ASYNC/LOGCMD" specifies that the program should run asynchronously and write the command line to a log file.
command — a string specifying the program or system command to invoke. If the full path to an executable is not specified, the operating system will apply standard search path rules.
arguments — command arguments are specified as a series of comma-delimited expressions (as demonstrated in the example below).
The $ZF(-100) function returns an exit status code determined by the operating system and the program that was invoked.
The following example passes three strings to the echo command and then displays the status code. This example does not use any keywords, so the keywords argument is an empty string. The final command argument specifies a quoted string (following standard ObjectScript string rules):
USER>set status = $ZF(-100,"","echo","hello","world","""goodbye now""")
hello world "goodbye now"
The following sections provide more examples for various $ZF(-100) options. See “$ZF(-100): Running Programs or System Commands” in the Callout Quick Reference chapter for a summary of keywords and other options.
$ZF(-100) allows you to run a program or command either synchronously or asynchronously, with or without invoking the operating system shell. The default is to execute synchronously without invoking a shell. Default execution can be overridden by specifying optional keywords in the function call.
The following keywords can be used to control program execution:
/ASYNC — Indicates that the program should run asynchronously, allowing the $ZF(-100) call to return without waiting for the program to complete.
/SHELL — Indicates that the program should run in an operating system shell.
As mentioned in the last section, you can specify an empty string for the keyword parameter if you don’t want to use either of these options. This example deliberately tries to list nonexistent files so that an error code 1 will be generated:
USER>set status = $ZF(-100,"", "ls","*.scala")
ls: cannot access *.scala: No such file or directory
If we run the same command asynchronously, the output is not displayed and status is undefined because no error code has been returned:
USER>set status = $ZF(-100,"/ASYNC", "ls","*.scala")
See “Using I/O Redirection” in the next section for a way to redirect error output in situations like this.
Logging Commands and Redirecting Output
The following keywords control logging and I/O redirection:
/LOGCMD — causes the program command and arguments to be sent to the messages log.
/STDIN, /STDOUT, and /STDERR— are used to redirect standard input, standard output, and standard error for the program invoked. These keywords must be followed by a file specification (see “Using I/O Redirection” below).
Logging Command Arguments
The /LOGCMD keyword causes command arguments and the exit status code to be logged in the messages log (<install-dir>\mgr\messages.log). This is intended primarily as a debugging tool that allows you to see how expressions passed to $ZF(-100) were actually evaluated.
In most cases, the command and its arguments are logged on one line, and the return value on the next. For example, set status=$ZF(-100,"/LOGCMD","echo","hello","world") produces the following log entry under Windows:
03/28/18-11:49:51:898 (26171) 0 $ZF(-100) cmd=echo "hello" "world"
03/28/18-11:49:51:905 (26171) 0 $ZF(-100) ret=0
However, on UNIX® when /SHELL is not specified, values are logged one per line:
03/28/18-12:09:22:243 (26171) 0 $ZF(-100) argv=echo
03/28/18-12:09:22:500 (26171) 0 $ZF(-100) argv=hello
03/28/18-12:09:22:559 (26171) 0 $ZF(-100) argv=world
03/28/18-12:09:22:963 (26171) 0 $ZF(-100) ret=0
In either case, arguments are logged exactly as they are received by the program.
Using I/O Redirection
The following keywords and file specifiers control I/O redirection:
I/O redirection keywords are followed by an operator ( = or += ) and a filename or file path. Spaces are permitted around the operators. Standard input should point to an existing file. The standard output and standard error files are created if they don't exist and are truncated if they already exist. Use the = operator to create or truncate a file, or the += operator to append to an existing file. To make standard error and standard output to go to the same file, specify the same file for both keywords.
In the following example, the first line redirects the standard output from the echo command to file temp.txt., and the second line displays the resulting file contents:
USER>set status = $ZF(-100,"/STDOUT=""temp.txt""","echo","-e","three\ntwo\none\nblastoff")
USER>set status = $ZF(-100,"","cat","temp.txt")
In this next example, we display two lines of temp.txt in a different way, by redirecting the file to standard input. The tail command accepts the input and displays the last two lines:
This final example redirects standard error to temp.txt, and attempts to display a nonexistent file. It also uses the /ASYNC keyword to run the command asynchronously, causing the $ZF(-100) call to return before the error message can be displayed. The second line (identical to the previous example) again displays the last two lines of the file, which now contain the redirected error message:
USER>set status = $ZF(-100,"/ASYNC /STDERR+=""temp.txt""","cat","nosuch.file")
cat: nosuch.file: No such file or directory
Adding the %System_Callout:USE Privilege
$ZF(-100) requires the %System_Callout:USE privilege. If your InterSystems security setting is higher than minimal, this privilege may be disabled. The following procedure describes how to enable it in the %Developer role:
Enabling %System_Callout:USE in the %Developer role
In the Management Portal go to System Administrator > Security > Roles.
On the Roles page, click on %Developer in the Names column.
On the General tab of the Edit %Developer page, find the %System_Callout privilege and click Edit
In the Edit resource permissions dialog, select the Permissions Use checkbox if not already selected, and click OK.
The %Developer role is always created for you when you install InterSystems IRIS, but administrators may not want to make it available to all users. In some cases, it may be desirable to provide users with a role that makes $ZF(-100) available but does not grant any other privileges. The following procedure creates a new role that grants only the %System_CallOut:USE privilege:
Enabling %System_Callout:USE in a New Role
Open the Management Portal and go to System Administration > Security > Roles.
On the Roles page, click the Create New Role button to bring up the Edit Roles page.
Fill in the name and description:
When you click Save, an Add button appears on the form.
Click the Add button to pop up a scrolling list of resources, select %System_CallOut from the list, and click Save. Click Close on the Edit Role form.
On the Roles page, the new UseCallout role is now in the list of role definitions.