exec_function
Table of Contents
# $EPIC: exec_function.txt,v 1.4 2006/08/29 18:22:56 sthalik Exp $
Synopsis:
$exec(<program> <args>)
Technical:
- If the <program> argument is ommited, the empty string is returned.
- Otherwise, <program> is forked and executed with <args> for arguments.
- This function returns 3 (three) FDs, which are pipes to/from STDIN, STDOUT and STDERR of the forked process respectively.
- The first FD returned (STDIN) is a write mode FD.
- The subsequent FDs (STDOUT and STDERR) are read mode FDs.
- Writing to a pipe that is full will cause epic to block.
- Reading from a pipe that is empty will cause epic to block.
- When epic is blocked waiting for a <program> which is also blocked waiting for epic, deadlock will occur. This is where the danger of this function lies.
- The write pipes will remain full while <program> is not emptying them by reading or closing them.
- The read pipes will remain empty while <program> is not filling them by writing or closing them.
- The only guaranteed way to prevent deadlock is to examine the way the program reads and writes its input/output and write your script to avoid the traps listed above.
- This function is relatively new. The /exec command may be better suited to your needs given the semantic difficulty of coding with this function.
- Unlike the /exec command, <program> will not be running under a shell. To emulate this feature, use $exec(sh -c “<program> <args>”).
Practical:
This function offers an easier interface and a finer grain control over the process than /exec, but comes at the expense of being more dangerous to use.
You could use this function to implement real time text filtering or scrambling using the unix tool “sed” perhaps.
$exec() might be a better alternative to $perl() and $tcl() for people who wish to distribute their scripts and need a certain level of compatibility that the embedded languages don't provide.
Returns:
One writable FD and two readable FDs.
Examples:
# # An example of what we can expect. # fe ($exec(tr a-zA-Z A-Za-z)) fd { echo $write($fd qwerASDF):$read($fd):$close($fd) } # # Output # Out1: 9::0 # STDIN wrote 9 bytes (including NL), read failed, Out2: -1:QWERasdf:0 # STDOUT write failed, read 9 bytes, Out3: -1::0 # STDERR write failed, read nothing, # FD close succeeded in all cases. # # Fortunately for us, md5sums i/o is very predictable. It, like # some other programs uses the EOF of its input as a signal to start # delivering output, so it is always safe for $exec() so long as we # do not attempt to read its output before closing its input. # # Note that the technique we use here can be used for most programs # and all filters if we restrain ourselves from writing too much data # to STDIN. Exactly how much data can be written depends on the "pipe # size" ulimit which can be changed with the ulimit command in any(?) # bourne compatible shell. # # Also note that in these examples, the FDs that aren't used are # closed before processing begins rather than after. It is # important to do this because if the program tries to read/write # a closed FD, it will always return immediately rather than # blocking. alias md5 { # a fast way to set three local variables. fe ($exec(md5sum)) in out err {break} @ close($err) @ write($in $*) @ close($in) @ function_return = read($out) @ close($out) } # # Translate upper to lower and lower to upper using a perl script. # The critical thing about this alias is the $|=1 in the perl script, # which turns autoflush on so that we receive the output immediately # after feeding it the input. The gnu tr command cannot be made to # do this, which makes it unsuitable for this application. # # Anyway, the reason this is critical is that we're going to $exec() # the perl script outside of the alias, perhaps at bootup, and leave # it running in the background forever with the assumption that every # line we give it is going to give us precisely one line back. Of # course, this is a very delicate thing since errors are going to # accumulate. # # Also, note the double quotes where we might normally use single # quotes in the shell. The input is broken into arguments according # to epics "word" rules. There is no equivalent to the single quotes # under these rules, though you can escape "quoting hell" by wrapping # the relevant parts of your script in braces like I have for this # example. # fe ($exec(perl -lpe "BEGIN{$|=1};{tr/a-zA-Z/A-Za-z/}")) in out err { @ ::transcase.in = in @ ::transcase.out = out @ close($err) break } alias transcase { @ write($transcase.in $*) return $read($transcase.out) }
exec_function.txt · Last modified: 2006/08/29 20:18 by 127.0.0.1