PIPESTATUS clarification

Dazed_75 lthielster at gmail.com
Tue Oct 5 11:51:54 MST 2010


This is a nit, but where Hans referred to "pipe commands", I would use
"piped commands".  To me, the pipe "commands" would be the '|' symbols
themselves for invoking the pipes.  Not important, just my grammatical
foible.

Hans gave this example:

( ls /tmp/afjkasdlf | grep georg | echo; pipestat=( ${PIPESTATUS[@]} );
> echo "<${pipestat[0]}>"; echo "<${pipestat[1]}>" )
>
> ls: cannot access /tmp/afjkasdlf: No such file or directory
> <2>
> <1>
>

At first I wondered why the pipe to echo.  I now understand it accomplishes
two things:
- prevents grep from displaying results by piping stdout to a command that
ignores stdin
- it outputs a blank line before the result of the commands in the pipe is
displayed
Though I am not sure why the blank line comes out before the error message
from ls. Probably has something to do with the way pipes function in
relation to stdout.

I also was confused because he ignored the piped command "echo" in his
explanation and it made me curious about more than just verifying what would
happen if each of the piped commands was made to fail or succeed by changing
the arguments.  I made a script called test based on derHans' example.

This made it easy to make mods in one window, save them and execute in a
terminal.  Pretty basic stuff.  After running a number of tests, I realized
it was not possible to see which version of test was used for each run n the
terminal.  So I added a cat test to the beginning of the script.  This
directory contains among other things the test script and some java error
logs named hs_err_pidnnnn.log.  The script was to show the return values for
all three piped commands plus a 4th just to see what would come out.

I saw some things that were hard to understand.

larry at triggerfish:~$ ./test
> cat test
>
> ( ls -l hs* | grep test | echo; pipestat=( ${PIPESTATUS[@]} );
> echo "ls rv=<${pipestat[0]}>"; echo "grep rv=<${pipestat[1]}>"; echo "echo
> rv=<${pipestat[1]}>"; echo "4th rv=<${pipestat[1]}>" )
>
> ls rv=<0>
> grep rv=<1>
> echo rv=<1>
> 4th rv=<1>
>
This came out as expected. ls found the error logs but grep found no
occurrences of "test"


> larry at triggerfish:~$ ./test
> cat test
>
> ( ls -l hs* | grep log | echo; pipestat=( ${PIPESTATUS[@]} );
> echo "ls rv=<${pipestat[0]}>"; echo "grep rv=<${pipestat[1]}>"; echo "echo
> rv=<${pipestat[1]}>"; echo "4th rv=<${pipestat[1]}>" )
>
> ls rv=<0>
> grep rv=<141>
> echo rv=<141>
> 4th rv=<141>
>
larry at triggerfish:~$ man grep
>
This was a complete surprise, grep should have succedded with multiple
occurrences of "log" and nothing in the man page for grep suggested a
meaning for the 141. Maybe it was the multiple files found, or multiple
finds by grep, or something about open files, or ...  So I tried a few
experiments:


> larry at triggerfish:~$ ./test
> cat test; sync
>
> ( ls -l test | grep test | echo; pipestat=( ${PIPESTATUS[@]} );
> echo "ls rv=<${pipestat[0]}>"; echo "grep rv=<${pipestat[1]}>"; echo "echo
> rv=<${pipestat[1]}>"; echo "4th rv=<${pipestat[1]}>" )
>
> ls rv=<0>
> grep rv=<0>
> echo rv=<0>
> 4th rv=<0>
>
So back to single files found and single grep results and with syncing (not
sure why I tried that) worked.


> larry at triggerfish:~$ ./test
> cat test;
>
> ( ls -l test | grep test | echo; pipestat=( ${PIPESTATUS[@]} );
> echo "ls rv=<${pipestat[0]}>"; echo "grep rv=<${pipestat[1]}>"; echo "echo
> rv=<${pipestat[1]}>"; echo "4th rv=<${pipestat[1]}>" )
>
> ls rv=<0>
> grep rv=<0>
> echo rv=<0>
> 4th rv=<0>
>
So did removing the sync. but leaving the semicolon.


> larry at triggerfish:~$ ./test
> cat test
>
> ( ls -l test | grep test | echo; pipestat=( ${PIPESTATUS[@]} );
> echo "ls rv=<${pipestat[0]}>"; echo "grep rv=<${pipestat[1]}>"; echo "echo
> rv=<${pipestat[1]}>"; echo "4th rv=<${pipestat[1]}>" )
>
> ls rv=<0>
> grep rv=<141>
> echo rv=<141>
> 4th rv=<141>
>
Aah, but dropping the semicolon caused the 141's and on a case that should
be all successes.

larry at triggerfish:~$ ./test
> cat test ;
>
> ( ls -l test | grep test | echo; pipestat=( ${PIPESTATUS[@]} );
> echo "ls rv=<${pipestat[0]}>"; echo "grep rv=<${pipestat[1]}>"; echo "echo
> rv=<${pipestat[1]}>"; echo "4th rv=<${pipestat[1]}>" )
>
> ls rv=<0>
> grep rv=<141>
> echo rv=<141>
> 4th rv=<141>
>
But so did putting it back but with whitespace before it.  Huh?


> larry at triggerfish:~$ ./test
> cat test;
>
> ( ls -l test | grep test | echo; pipestat=( ${PIPESTATUS[@]} );
> echo "ls rv=<${pipestat[0]}>"; echo "grep rv=<${pipestat[1]}>"; echo "echo
> rv=<${pipestat[1]}>"; echo "4th rv=<${pipestat[1]}>" )
>
> ls rv=<0>
> grep rv=<141>
> echo rv=<141>
> 4th rv=<141>
>
Ditto whith no white space.


> larry at triggerfish:~$ ./test
> cat test; sync
>
> ( ls -l test | grep test | echo; pipestat=( ${PIPESTATUS[@]} );
> echo "ls rv=<${pipestat[0]}>"; echo "grep rv=<${pipestat[1]}>"; echo "echo
> rv=<${pipestat[1]}>"; echo "4th rv=<${pipestat[1]}>" )
>
> ls rv=<0>
> grep rv=<141>
> echo rv=<141>
> 4th rv=<141>
>
and with a sync but no trailing semicolon


> larry at triggerfish:~$ ./test
> cat test; sync;
>
> ( ls -l test | grep test | echo; pipestat=( ${PIPESTATUS[@]} );
> echo "ls rv=<${pipestat[0]}>"; echo "grep rv=<${pipestat[1]}>"; echo "echo
> rv=<${pipestat[1]}>"; echo "4th rv=<${pipestat[1]}>" )
>
> ls rv=<0>
> grep rv=<0>
> echo rv=<0>
> 4th rv=<0>
> larry at triggerfish:~$
>
But adding a trailing semicolon fixed it again.

So it seems to me that there must be more than one behaviour involved.  It
as if the contents of PIPESTATUS and therefore of pipestat are affected by
things that happened and completed before the execution of the piped
commands.  Very puzzling to me!  Am I missing something basic?

-- 
Dazed_75 a.k.a. Larry

The spirit of resistance to government is so valuable on certain occasions,
that I wish it always to be kept alive.
  - Thomas Jefferson
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.PLUG.phoenix.az.us/pipermail/plug-discuss/attachments/20101005/ad7bda0b/attachment.html>


More information about the PLUG-discuss mailing list