Site Tools


exec_function
no way to compare when less than two revisions

Differences

This shows you the differences between two versions of the page.


exec_function [2006/08/29 20:18] (current) – created - external edit 127.0.0.1
Line 1: Line 1:
 +# $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.
 +   * The FDs returned can be used with $[[read]](), $[[write]](), etc, however...
 +   * 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|exec]] command may be better suited to your needs given the semantic difficulty of coding with this function.
 +   * Unlike the /[[exec command|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 command|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 function|perl]]() and
 +$[[tcl function|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:======
 +<file>
 +#
 +# 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: # 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)
 +}
 +</file>
  
exec_function.txt · Last modified: 2006/08/29 20:18 by 127.0.0.1