[comp.lang.icon] pipe opens

ron@mlfarm.com (Ronald Florence) (03/13/91)

I can't get this bit of code to work:

     procedure main()

       write(pipe("bogus-command", "nonsense", "logname"))
     end

     procedure pipe(cmd[])

       until inf := open(pop(cmd), "pr") 
       got := !inf
       close(inf)
       return got
     end

The idea is to try opening a pipe to a series of commands until one
succeeds.  It doesn't work (at least here), because instead of the
open() failing on "bogus-command" and "nonsense", the shell reports
that the command wasn't found.

Any idea how to do what I want to do?
--

Ronald Florence			ron@mlfarm.com

nowlin@isidev.UUCP (03/16/91)

> I can't get this bit of code to work:
> 
>      procedure main()
>        write(pipe("bogus-command", "nonsense", "logname"))
>      end
> 
>      procedure pipe(cmd[])
>        until inf := open(pop(cmd), "pr") 
>        got := !inf
>        close(inf)
>        return got
>      end
> 
> The idea is to try opening a pipe to a series of commands until one
> succeeds.  It doesn't work (at least here), because instead of the
> open() failing on "bogus-command" and "nonsense", the shell reports
> that the command wasn't found.
> 
> Any idea how to do what I want to do?
> --
> 
> Ronald Florence			ron@mlfarm.com

The problem is that the pipe-read in Icon invokes the command in a
sub-shell and the open of the sub-shell almost never fails.  That's why the
first bogus command in your list terminates the program.  The main reason
to test the success or failure of the open in this program is in case the
pop() fails.

The real way to test the success or failure of a command invoked with the
pipe-read is to check the return value from the close of the pipe.  This is
where the exit code of the command is returned.  For standard UNIX this
exit code should be zero if the command succeeded.

The second problem is that the "not found" error comes from the sub-shell
instead of the command being tested.  There's no (easy) way to redirect
that error output without invoking the command in a separate sub-shell.
The following program works that way.  I included three sets of test data
since the possibility of an infinite loop, if there's no command that
succeeds, should be tested:

    procedure main()

        write(pipe("bogus-command","nonsense","logname","more-junk"))
        write(pipe("bogus-command","nonsense","lognothing","more-junk"))
        write(pipe("logname","bogus-command","nonsense","more-junk"))

    end

    procedure pipe(cmd[])

        repeat {
            inf := open("(" || pop(cmd) || ") 2>&1","pr") | fail
            got := !inf
            if close(inf) = 0 then return got
        }

    end

This version of pipe() follows the basic algorithm you used.  I know the
order of precedence of the expression containing the open() is not obvious
here but once a procedure fails it fails.  It doesn't make any difference
if it's trying to assign the result of failure to a variable.

The following version of the pipe() procedure uses goal directed evaluation
instead of iteration.  I like this one better:

    procedure pipe(cmd[])

        if inf := open("(" || !cmd || ") 2>&1","pr") &
           got := !inf &
           close(inf) = 0 then
               return got

        else   fail

    end

+-------------------------------------------------------------------------+
|  --- ---                                                                |
|   | S |  Iconic Software, Inc.  -  Jerry Nowlin  - uunet!isidev!nowlin  |
|  --- ---                                                                |
+-------------------------------------------------------------------------+