From: anders@lise7.lise.unit.no (Anders Christensen)
Subject: Re: SH backquote functionality in REXX?
Organization: /home/flipper/anders/.organization
Date: 13 Aug 92 17:30:56

In article <41280@ogicse.ogi.edu> jbthiel@ogicse.ogi.edu (John B. Thiel) writes:

> What, if any, is a Rexx equivalent to the backquote mechanism as used
> in SH, whereby `process` is replaced by the stdio output of the
> process?
>
> eg.
> now=`date`

There aren't a Rexx equivalent, there are probably several, depending
on the Rexx implementation that you are using. According to "The REXX
Language" by M.F. Cowlishaw, Rexx allows external functions which may
be an external program, written in Rexx or in any other language that
"supports the implementation-dependent interfaces used by REXX to
invoke it." It is the duty of the command to be able to communicate
with the interpreter, not the other way around. 

So the only thing that you are guaranteed, is that if the external
program that you want to invoke is a Rexx script, then it will work.
If it is not a Rexx script, then the behavior is implementation
dependent. Sorry ... 

However, DON'T PANIC! Most implementation has some way to do this. The
ways differ, so it is hard to write compatible Rexx scripts to do
this. 

Let's take an example:

   Suppose you want to run the command 'hostname', which just writes
   out the name of the machine that you are using as output. The
   following *might* work:

      say 'My host is' hostname()

   Supposing that there are no labels called 'hostname' and no builtin
   functions called 'hostname'. It also requires that the command in
   your operating system can be accessed as "HOSTNAME" (Rexx always
   upper case unquoted names). If you use:

      say 'My host is' 'hostname'()

   It will work if there are no builtin function called 'hostname' and
   that the external function can be found using the name 'hostname'
   (note the lower case letters). 

In both these cases, you are only guaranteed success if 'hostname' is an
external Rexx program, if it is something else (let's say a compiled C
program), then you're at the mercy of the implementation. 

So, back to your example. You wanted to get output from the operating
system command 'date'. This is a real trap, for several reasons.

1) The clause   say 'DATE'()   will call the Rexx builtin function 
   date() in rexx, so you cat at least *never* use that.

2) The clause say 'date'() will *never* call the builtin function
   date() in rexx. But (depending on your opsys) it might not be the
   right case for the command to call (i.e. 'date' != 'DATE'). Since
   you are referring to the Bourne shell, I assume that you are using
   Unix, and then the lower case letters is exactly what you need.

3) At least on Unix systems, there might be a way around it, by using
   a path, and calling it as  '/bin/date'(). Then you will never crash
   into a builtin function.

4) On some systems certain command are 'builtin' in the external
   environment. Under Unix there are 'echo', 'time' and 'umask'; Under
   MS-DOS there are 'echo', 'time' and 'date', just to mention a few. 
   Whether or not you are able to reach these function depends
   completely on the implementation. 

5) Then there is the problem of sending parameters. At least on Unix
   machines, the command gets its parameter string chopped up in
   individual parameters. Let's assume that you want to run the
   command 'who' with the two parameters 'am' and 'I'. (A unix command
   that writes out you user name and a few other things.) Depending on
   the implementation, there are several ways to do this, e.g.

      say 'who'('am', 'I')   /* type one */
      say 'who'('am I')      /* type two */

   The first type is the 'correct' Rexx way to do it: Run 'who' with
   the two parameters 'am' and 'I', but it looks kind of ugly. The
   second type is more readable, but you depend on implicit rules for
   deciding where to divide the parameters (suppose you wanted a
   parameter containing a space?). 

   Actually, a type one interpreter getting a type two call, would
   call 'who' with the single parameter 'am I'. A type two interpreter
   getting a type one call might be capable to trap it and do the
   right thing. 

   To confuse even more ... the whole thing might also be dependent on
   which interface is used when calling the command. If it is called
   through a command interpreter, the second type call on a first type
   interpreter might work after all, since the command interpreter
   will parse the parameters.  (Then, even say  'who am I'()  would
   work). 

6) Unfortunately (or maybe fortunately), there are really no
   requirements in TRL that specify how external command are going to
   be interpreted. In fact, there is not even any grounds to claim
   that the ADDRESS clause will effect the choice of what environment
   functions are sent to.
   
That was the first method. The second method, which may (or may not)
work if the first method does not work, is to run the command and
flush the output to the stack, an then pull the result that you want. 
Unfortunately, there are even more problems in this area ...

1) Most operating system don't know of the concept of a stack, so in
   some Rexx interpreters there are kludged in ways to redirect the
   output and input to and from the stack. In REXX/imc you would do
   something like

      'date | rxstack'
      parse pull line

   while in Regina, you would do something similar (in syntax):

      'date >LIFO'
      parse pull line

   and in other rexx interpreters, you would probably do it in some
   other manner.

2) Interpreters that don't kludge the stack concept into their
   commands, may use another strategy, like that of uni-REXX, which
   uses the function popen() to run a command with output to the
   stack. The parameter of popen() is the command to run, like:

      junk = popen('date')
      parse pull line 

3) Some operating systems that *do* know the stack concept, often
   offer options to their commands, like CMS's '(STACK' or '(LIFO'
   which enables the user to request that the output from that command
   is put on the stack. 

If you really want to write compatible code, you'll probably want to
avoid the whole problem, and just use the builtin function date(). 

-anders
Comments: Gated by NETNEWS@AUVM.AMERICAN.EDU