# system_exec

Definition: | integer exit_code = system_exec(string st, integer mode=2, sequence pipes={})
Description: | Execute the specified command string.
pwa/p2js: | Not supported.
Comments: | Any path or filename containing spaces should be enclosed in quotation marks, as shown in example 3. The system_exec() routine can actually be run in four different ways, depending on whether you want a result and whether a command shell is required. The `system(st)` routine is in fact a simple wrapper of system_exec that creates a new shell and does not wait for a return value. In contrast `res = system_exec(st)`, ie using the default mode, does not create a new shell and waits for a return value. The bit settings of the mode parameter are designed to implement the above (default) behaviours, and in a backwards-compatible manner, but as a result are slightly unusual and easiest to explain using the table below. The legacy mode parameter values of 0, 1, and 2, which controlled the restoration of the graphics mode, are now completely ignored, as the fullscreen video mode of an MS_DOS window has not been available since the release of Windows Vista (Jan 2007). Bit #04 controls whether a new shell is created (1=yes) and bit #08 controls whether to wait for a (meaningful) return value (1=no). The opposing on/off meanings of a set bit are a potential source of confusion, however all legacy code should continue to work unaltered. If bit #04 in mode is set, a new shell is started, using %COMSPEC% /C, which means it has the same features (redirection, wildcards, etc) and is subject to the same limitations (eg it was 126 chars on Win98, but has grown to 8000 chars on Win7) as manually using an MS-DOS console window. This is the (non-overrideable) behaviour of system(). If bit #04 in mode is not set, no new shell is started, in which case st must be a .exe or .com program. Attempts to run .bat files, built-in DOS commands, or use command-line redirection will fail (unless you have manually prefixed the command with %COMSPEC% /C). Some commands, such as DEL, are not programs, they are actually built-in to the command interpreter. This is the default behaviour for system_exec(). If bit #08 in mode is set, this routine does not wait for the command to finish (though it does allow it 0.4s to get going, unless bit #10 is also set) and the return value is a process handle or -1. This is the (non-overrideable) behaviour of system(). If bit #08 in mode is not set, this routine waits for the command to finish and returns the appropriate exit code, typically in the range 0 to 255, with 0 indicating success. This is the default behaviour for system_exec(). If it is not possible to run the program, system_exec() returns -1 (whether bit #08 was set or not). The following table shows the four possible ways that system_exec can be used, one of which is the same as "system() plus -1":
result/wait | redirect/builtin | invoke | aka
no | yes | system(st) | res1 = system_exec(st,12) (or #1C)
no | no |  | res1 = system_exec(st,8) (or #18)
yes | yes |  | res = system_exec(st,4)
yes | no | system_exec(st) | res = system_exec(st[,0])
1 -1 if the command could not be invoked, otherwise a process handle. In the first case (system/12) a non-(-1) result only means it successfully created a shell, as opposed to the shell being able to make any sense of the rest of the line. Note that the process handle will be for the shell, rather than any processes the shell might initiate. Note that the bit 4/8/10 settings of the mode parameter have no known equivalents on Euphoria, though otherwise system() and system_exec() work the same. Bit #10 is completely ignored unless bit #08 is also set. When bit 8 is set you should expect any files it uses/creates to still be in use; when bit #10 is also set there is a high probability any such will not even have been opened yet, and should multiple spawned instances start fighting over files/locks/anything, that’s on you. For example if you want to run DEL or a batch file or the command string contains "< input" or "> output", then you need system_exec(st,4) (if you want a result) or system (if you do not), and both of those come with that "ugly black box" thing as part and parcel of the deal for the extra functionality. If however you want to run an exe file then system_exec(st,[#1]8) (no result, returns immediately), or system_exec (result, does not return until the invoked executable terminates) may be more appropriate, and without an "ugly black box" - unless triggered by something like ?, puts(1,xx) or getc(0). See demo\capture_console.exw for a detailed example of using the pipes parameter (needs a bit more work on linux). If provided, it should be a sequence of length 3 for stdin/stdout/stderr, each of which is either a pair of read/write pipe handles or 0/NULL if that does not want redirecting. Note that when both waiting for a result and redirecting stdin, all output to the latter must be completed before the call to system_exec(), or perhaps via separate threads (but not tasks). For example, to only capture/redirect stdout, it should be {0,{stdout_rd,stdout_wr},0}, where stdout_rd and stdout_wr are from create_pipe() [DEV not yet a builtin, the one in capture_console.exw is a potential candidate]. You can run a Phix program using system_exec(), and it can return an exit code using abort(). system_exec() does not by default start a new DOS shell.
Example 1: |
    integer exit_code
    exit_code = system_exec("xcopy temp1.dat temp2.dat")
    if exit_code=-1 then
        puts(2, "\n couldn't run xcopy.exe\n")
    elsif exit_code=0 then
        puts(2, "\n xcopy succeeded\n")
    else
        printf(2, "\n xcopy failed with code %d\n", exit_code)
    end if
Example 2: |
    -- executes myprog with two file names as arguments
    if system_exec(`p.exe \test\myprog.ex indata.csv outdata.csv`) then
        puts(2, "failure!\n")
    end if
Example 3: |
    -- execute myprog with redirected standard input and output, and wait for the result
    -- note the use of quotation marks around any path/filename that contains spaces
    if system_exec(`"C:Program Files (x86)\Phix\p.exe" myprog.ex < indata > outdata`,4)
        puts(2, "failure!\n")
    end if
Implementation: | See builtins\syswait.ew (an autoinclude) for details of the actual implementation.
See Also: | system, abort, get_interpreter