Re: [Help-bash] difference of $? and ${PIPESTATUS[0]}

2024-04-22 Thread Chet Ramey

On 4/22/24 2:13 AM, felix wrote:


I could explain that '$?' is result of bash's if...then...fi group command
executed correctly and PIPESTATUS hold result of "most-recently-executed
foreground pipeline", but man page say:

 PIPESTATUS
  An  array  variable (see Arrays below) containing a list of exit
  status values from the processes in  the  most-recently-executed
  foreground pipeline (which may contain only a single command).

  ?   Expands  to  the exit status of the most recently executed fore‐
  ground pipeline.


It's clumsy wording, no doubt, but the two aren't intended to be the same
or necessarily have the same value.

The language in the description of $? is very close to POSIX, since the
POSIX grammar basically makes any command a pipeline. It's formal so the
standard can relate it to the grammar, but very few people think of

if a; then echo b; else echo c; fi

as a `pipeline'.



If so, "$?" have to be equivalent to "${PIPESTATUS[0]}", I think.


No, even if this were true, it would be the last member of PIPESTATUS,
modulo the `pipefail' setting.


I suggest that man page should be modified to replace "foreground pipeline"
by "command" under "?" paragraph.


Yeah, that's probably closer to the real meaning. The description of
PIPESTATUS refers to pipelines as described in Pipelines under SHELL
GRAMMAR (which can also be a Simple Command from the same section).

--
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRUc...@case.eduhttp://tiswww.cwru.edu/~chet/



OpenPGP_signature.asc
Description: OpenPGP digital signature


Re: [Help-bash] difference of $? and ${PIPESTATUS[0]}

2024-04-22 Thread Kerin Millar
On Mon, 22 Apr 2024, at 8:56 AM, Oğuz wrote:
> On Mon, Apr 22, 2024 at 10:24 AM Kerin Millar  wrote:
>> I cannot find anything in the manual that concretely explains why bash 
>> behaves as it does in this instance.
>
> Me neither, but the current behavior is useful. Take `while false |

Very much so. The clarity of the documentation is my only concern.

-- 
Kerin Millar



Re: [Help-bash] difference of $? and ${PIPESTATUS[0]}

2024-04-22 Thread Greg Wooledge
On Mon, Apr 22, 2024 at 08:13:16AM +0200, felix wrote:
> Then after some tests:
> 
>   if ls /wrong/path | wc | cat - /wrong/path | sed 'w/wrong/path' >/dev/null 
> ; then
>   echo Don't print this'
>   fi ; echo ${?@Q} ${PIPESTATUS[@]@A}  $(( $? ${PIPESTATUS[@]/#/+} ))
> 
>   ls: cannot access '/wrong/path': No such file or directory
>   cat: /wrong/path: No such file or directory
>   sed: couldn't open file /wrong/path: No such file or directory
>   '0' declare -a PIPESTATUS=([0]="2" [1]="0" [2]="1" [3]="4") 7
> 
> Where $PIPESTATUS[0]=>2 and $?=>0 !!
> 
> I could explain that '$?' is result of bash's if...then...fi group command
> executed correctly [...]

That is indeed the issue here.  $? contains the exit status of the "if"
command, not of the pipeline.

hobbit:~$ help if
[...]
The exit status of the entire construct is the exit status of the
last command executed, or zero if no condition tested true.
[...]

hobbit:~$ if (exit 42); then :; fi
hobbit:~$ echo $?
0

If you remove the 'if' from your example, you get a very different result:

hobbit:~$ /wrong/path | wc | cat - /wrong/path | sed 'w/wrong/path' >/dev/null
bash: /wrong/path: No such file or directory
sed: couldn't open file /wrong/path: No such file or directory
hobbit:~$ echo "<$?> <${PIPESTATUS[@]@A}>"
<4> 

Here, $? is the exit status of the last command in the pipeline, as
it should be.

I don't know where your notion that $? and PIPESTATUS[0] should be
equivalent came from, but it is never right, except in the case where the
"pipeline" is just a single command.

Introducing the 'if' separates the value of $? and the values of the
PIPESTATUS array entirely.  They no longer refer to the same pipeline
at all.  $? contains the exit status of 'if' itself, and PIPESTATUS
contains the exit statuses of the commands from the pipeline.  If
you want $? to contain the exit status of the pipeline instead, you
need to reference it from within the 'if' statement.

hobbit:~$ if (exit 42); then echo "yes $?"; else echo "no $?"; fi
no 42

Once the 'if' terminates, the exit status of the pipeline is no longer
reliably available through $?.



Re: [Help-bash] difference of $? and ${PIPESTATUS[0]}

2024-04-22 Thread Martin D Kealey
On Mon, 22 Apr 2024, 18:13 felix,  wrote:

> Hi,
>
> Coming on this very old thread:
>
> [the] man page say[s]:
>
> PIPESTATUS
>  An  array  variable (see Arrays below) containing a list of exit
>  status values from the processes in  the  most-recently-executed
>  foreground pipeline (which may contain only a single command).
>
>  ?   Expands  to  the exit status of the most recently executed fore‐
>  ground pipeline.
>
> If so, "$?" have to be equivalent to "${PIPESTATUS[0]}", I think.
>
> I suggest that man page should be modified to replace "foreground pipeline"
> by "command" under "?" paragraph.


Ironically the description of ? is correct, subject to understanding shopt
-u lastpipe, but the description of LASTPIPE is incongruent with the
meanings of "pipeline", and that the status of a compound command is the
status of its last inner command not counting any command whose status is
checked by the compound command itself (so commands immediately followed by
";do", ";then", or ";else" do not contribute to the status of the compound
command).

On the other hand, LASTPIPE is set after a simple command, ignoring any '!'
or 'time' prefix, or any (explicit or implicit) subshell because a
subshell's exit status is reported via exit+wait in the same manner as a
simple command).

That in turn implies that it will be set after any non-trivial pipeline,
because that forces each of its parts to be executed as a subshell.

-Martin


Re: [Help-bash] difference of $? and ${PIPESTATUS[0]}

2024-04-22 Thread felix
Le Mon, Apr 22, 2024 at 10:56:03AM +0300, Oğuz a écrit :
> 
> Me neither, but the current behavior is useful.
I agree!

Anyway, reading man page, `$?` have to be equivalent to `${PIPESTATUS[-1]}`!
which is not always the case.

> I've never seen anything like that in a real shell script.
I have to confess my neither, upto this post on SO, more than ten years later!

-- 
 Félix Hauri  --  http://www.f-hauri.ch



Re: [Help-bash] difference of $? and ${PIPESTATUS[0]}

2024-04-22 Thread Oğuz
On Mon, Apr 22, 2024 at 10:24 AM Kerin Millar  wrote:
> I cannot find anything in the manual that concretely explains why bash 
> behaves as it does in this instance.

Me neither, but the current behavior is useful. Take `while false |
false; do :; done' for example, if bash reported the status of the
while command in PIPESTATUS you couldn't tell which part of your
condition failed. This isn't reliable when the lastpipe shell option
is in effect and you have `some command | break' in your loop body but
I've never seen anything like that in a real shell script.



Re: [Help-bash] difference of $? and ${PIPESTATUS[0]}

2024-04-22 Thread Andreas Kähäri
On Mon, Apr 22, 2024 at 09:15:52AM +0200, felix wrote:
> Le Mon, Apr 22, 2024 at 07:44:48AM +0100, Kerin Millar a écrit :
> > On Mon, 22 Apr 2024, at 7:13 AM, felix wrote:
> > > ...
> > >   if ls /wrong/path | wc | cat - /wrong/path | sed 'w/wrong/path' 
> > > >/dev/null ; then
> > >   echo Don't print this'
> > >   fi ; echo ${?@Q} ${PIPESTATUS[@]@A}  $(( $? ${PIPESTATUS[@]/#/+} ))
> > >
> > >   ls: cannot access '/wrong/path': No such file or directory
> > >   cat: /wrong/path: No such file or directory
> > >   sed: couldn't open file /wrong/path: No such file or directory
> > >   '0' declare -a PIPESTATUS=([0]="2" [1]="0" [2]="1" [3]="4") 7
> > >
> > > Where $PIPESTATUS[0]=>2 and $?=>0 !!
> > > ...
> > > If so, "$?" have to be equivalent to "${PIPESTATUS[0]}", I think.
> > 
> > No. That would only be true in the event that the pipeline comprises a 
> > single command. The present documentation is correct.
> 
> I was wrong: the last is `${PIPESTATUS[-1]}' -> '${PIPESTATUS[3]}' in this 
> case,
> anyway
>  $PIPESTATUS[3]=>4 and $?=>0 !!
> 
> > It's worth reading the section of the manual that concerns "Pipelines".
> Reading this, if I could understand why
>   false;echo ${PIPESTATUS[0]} $?
>   1 1
> I'm still don't be able to explain this:
>   if false;then echo Don't print that's;fi; echo ${PIPESTATUS[0]} $?
>   1 0
> 
> -- 
>  Félix Hauri  --  http://www.f-hauri.ch

The exit status of an "if" statement is the exit status of the last
command executed within the body of the statement.

In your last example, nothing is executed by the body of the "if"
statement, so the exit status of the statement is zero.

>From the bash manual about this in the "Compound Commands" section:

The exit status is the exit status of the last command
executed, or zero if no condition tested true.

The PIPESTATUS array is set by virtue of executing the "false" command
in the "if"-satement's test.

-- 
Andreas (Kusalananda) Kähäri
Uppsala, Sweden

.



Re: [Help-bash] difference of $? and ${PIPESTATUS[0]}

2024-04-22 Thread Kerin Millar
On Mon, 22 Apr 2024, at 7:44 AM, Kerin Millar wrote:
> On Mon, 22 Apr 2024, at 7:13 AM, felix wrote:
>> Hi,
>>
>> Comming on this very old thread:
>>
>> On Wed, 4 Dec 2013 14:40:11 -0500, Greg Wooledge wrote:
>>> 
>>> The most obvious difference is that $? is shorter.
>>> 
>>> $? is also POSIX standard (older than POSIX in fact), so it works in sh
>>> scripts as well.  PIPESTATUS is a Bash extension.
>>> 
>>> Finally, note that if you execute a pipeline, $? will contain the exit
>>> status of the last command in the pipeline, not the first command,
>>> which is what ${PIPESTATUS[0]} would contain.  (If you execute a simple
>>> command instead of a pipeline, then they would both have the same value.)
>>
>> Some asked on StackOverflow.com:
>>   Why does a Bash while loop result in PIPESTATUS "1" instead of "0"?
>>   https://stackoverflow.com/q/78351657/1765658
>>
>> Then after some tests:
>>
>>   if ls /wrong/path | wc | cat - /wrong/path | sed 'w/wrong/path' 
>> >/dev/null ; then
>>   echo Don't print this'
>>   fi ; echo ${?@Q} ${PIPESTATUS[@]@A}  $(( $? ${PIPESTATUS[@]/#/+} ))
>>
>>   ls: cannot access '/wrong/path': No such file or directory
>>   cat: /wrong/path: No such file or directory
>>   sed: couldn't open file /wrong/path: No such file or directory
>>   '0' declare -a PIPESTATUS=([0]="2" [1]="0" [2]="1" [3]="4") 7
>>
>> Where $PIPESTATUS[0]=>2 and $?=>0 !!

I just looked at the the Stack Overflow thread. It's not explained by forking, 
at least. Here's a simpler test case, using the true and false builtins.

$ if false; then true; fi
$ echo "$?" "${PIPESTATUS[@]@Q}"
0 '1'

Clearly, ? shows the exit status of if, whereas PIPESTATUS shows the exit 
status of false, which counts as a foreground pipeline in its own right. I 
presume that this is by design but I must agree that it is surprising. I cannot 
find anything in the manual that concretely explains why bash behaves as it 
does in this instance.

Here is another case in which the pipeline comprises two compound commands, 
with the values of $? and PIPESTATUS being exactly as one would expect.

$ if false; then true; fi | if true; then false; fi; echo "$?" 
"${PIPESTATUS[@]@Q}"
1 '0' '1'

-- 
Kerin Millar



Re: [Help-bash] difference of $? and ${PIPESTATUS[0]}

2024-04-22 Thread felix
Le Mon, Apr 22, 2024 at 07:44:48AM +0100, Kerin Millar a écrit :
> On Mon, 22 Apr 2024, at 7:13 AM, felix wrote:
> > ...
> >   if ls /wrong/path | wc | cat - /wrong/path | sed 'w/wrong/path' 
> > >/dev/null ; then
> >   echo Don't print this'
> >   fi ; echo ${?@Q} ${PIPESTATUS[@]@A}  $(( $? ${PIPESTATUS[@]/#/+} ))
> >
> >   ls: cannot access '/wrong/path': No such file or directory
> >   cat: /wrong/path: No such file or directory
> >   sed: couldn't open file /wrong/path: No such file or directory
> >   '0' declare -a PIPESTATUS=([0]="2" [1]="0" [2]="1" [3]="4") 7
> >
> > Where $PIPESTATUS[0]=>2 and $?=>0 !!
> > ...
> > If so, "$?" have to be equivalent to "${PIPESTATUS[0]}", I think.
> 
> No. That would only be true in the event that the pipeline comprises a single 
> command. The present documentation is correct.

I was wrong: the last is `${PIPESTATUS[-1]}' -> '${PIPESTATUS[3]}' in this case,
anyway
 $PIPESTATUS[3]=>4 and $?=>0 !!

> It's worth reading the section of the manual that concerns "Pipelines".
Reading this, if I could understand why
  false;echo ${PIPESTATUS[0]} $?
  1 1
I'm still don't be able to explain this:
  if false;then echo Don't print that's;fi; echo ${PIPESTATUS[0]} $?
  1 0

-- 
 Félix Hauri  --  http://www.f-hauri.ch



Re: [Help-bash] difference of $? and ${PIPESTATUS[0]}

2024-04-22 Thread Kerin Millar
On Mon, 22 Apr 2024, at 7:13 AM, felix wrote:
> Hi,
>
> Comming on this very old thread:
>
> On Wed, 4 Dec 2013 14:40:11 -0500, Greg Wooledge wrote:
>> 
>> The most obvious difference is that $? is shorter.
>> 
>> $? is also POSIX standard (older than POSIX in fact), so it works in sh
>> scripts as well.  PIPESTATUS is a Bash extension.
>> 
>> Finally, note that if you execute a pipeline, $? will contain the exit
>> status of the last command in the pipeline, not the first command,
>> which is what ${PIPESTATUS[0]} would contain.  (If you execute a simple
>> command instead of a pipeline, then they would both have the same value.)
>
> Some asked on StackOverflow.com:
>   Why does a Bash while loop result in PIPESTATUS "1" instead of "0"?
>   https://stackoverflow.com/q/78351657/1765658
>
> Then after some tests:
>
>   if ls /wrong/path | wc | cat - /wrong/path | sed 'w/wrong/path' 
> >/dev/null ; then
>   echo Don't print this'
>   fi ; echo ${?@Q} ${PIPESTATUS[@]@A}  $(( $? ${PIPESTATUS[@]/#/+} ))
>
>   ls: cannot access '/wrong/path': No such file or directory
>   cat: /wrong/path: No such file or directory
>   sed: couldn't open file /wrong/path: No such file or directory
>   '0' declare -a PIPESTATUS=([0]="2" [1]="0" [2]="1" [3]="4") 7
>
> Where $PIPESTATUS[0]=>2 and $?=>0 !!
>
> I could explain that '$?' is result of bash's if...then...fi group command
> executed correctly and PIPESTATUS hold result of "most-recently-executed
> foreground pipeline", but man page say:
>
> PIPESTATUS
>  An  array  variable (see Arrays below) containing a list of exit
>  status values from the processes in  the  most-recently-executed
>  foreground pipeline (which may contain only a single command).
>
>  ?   Expands  to  the exit status of the most recently executed fore‐
>  ground pipeline.
>
> If so, "$?" have to be equivalent to "${PIPESTATUS[0]}", I think.

No. That would only be true in the event that the pipeline comprises a single 
command. The present documentation is correct.

>
> I suggest that man page should be modified to replace "foreground pipeline"
> by "command" under "?" paragraph.

It's worth reading the section of the manual that concerns "Pipelines". Not 
least, to concretely understand what they are in grammatical terms, but also to 
understand that the exit status of a pipeline is "the exit status of the last 
command, unless the pipefail option is enabled". That is, the last command that 
constitutes the pipeline; there need not be more than one.

-- 
Kerin Millar



Re: [Help-bash] difference of $? and ${PIPESTATUS[0]}

2024-04-22 Thread felix
Hi,

Comming on this very old thread:

On Wed, 4 Dec 2013 14:40:11 -0500, Greg Wooledge wrote:
> 
> The most obvious difference is that $? is shorter.
> 
> $? is also POSIX standard (older than POSIX in fact), so it works in sh
> scripts as well.  PIPESTATUS is a Bash extension.
> 
> Finally, note that if you execute a pipeline, $? will contain the exit
> status of the last command in the pipeline, not the first command,
> which is what ${PIPESTATUS[0]} would contain.  (If you execute a simple
> command instead of a pipeline, then they would both have the same value.)

Some asked on StackOverflow.com:
  Why does a Bash while loop result in PIPESTATUS "1" instead of "0"?
  https://stackoverflow.com/q/78351657/1765658

Then after some tests:

  if ls /wrong/path | wc | cat - /wrong/path | sed 'w/wrong/path' >/dev/null ; 
then
  echo Don't print this'
  fi ; echo ${?@Q} ${PIPESTATUS[@]@A}  $(( $? ${PIPESTATUS[@]/#/+} ))

  ls: cannot access '/wrong/path': No such file or directory
  cat: /wrong/path: No such file or directory
  sed: couldn't open file /wrong/path: No such file or directory
  '0' declare -a PIPESTATUS=([0]="2" [1]="0" [2]="1" [3]="4") 7

Where $PIPESTATUS[0]=>2 and $?=>0 !!

I could explain that '$?' is result of bash's if...then...fi group command
executed correctly and PIPESTATUS hold result of "most-recently-executed
foreground pipeline", but man page say:

PIPESTATUS
 An  array  variable (see Arrays below) containing a list of exit
 status values from the processes in  the  most-recently-executed
 foreground pipeline (which may contain only a single command).

 ?   Expands  to  the exit status of the most recently executed fore‐
 ground pipeline.

If so, "$?" have to be equivalent to "${PIPESTATUS[0]}", I think.

I suggest that man page should be modified to replace "foreground pipeline"
by "command" under "?" paragraph.


-- 
 Félix Hauri  --  http://www.f-hauri.ch