Bug in bash? different from ksh, at any rate...

Rick Thomas's picture

Forums: 

Can anybody explain this difference between the behavior of bash and
ksh?

When reading the man page, I would expect both of them to have the
behavior exhibited by ksh.
Why does bash seem to treat "return" like a single level "break" in
this context?

The "echo "$AA" | while read" is important context. If I change it to
"for i in 0 1", return does as expected.

If it's any help, changing "return" to "break 2" doesn't help. with
bash, it still gives "1 1 1 1"
while ksh still gives "1"

I wonder if it has anything to do with "while read" causing a subshell
to be created, and bash getting confused about the "return" inside of
a subshell. If so, it's a bug in bash that ksh gets right, so it
ought to be fixable.

ADVthanksANCE

Rick

----------- example of strange behavior below -----------

:~$ cat /tmp/testit
function strange {
for j in 0 1 2 3
do
AA=' 1
2'
echo "$AA" | while read i
do
echo "$i"
return
done
done
}
echo $(strange)

:~$ bash /tmp/testit
1 1 1 1

:~$ ksh /tmp/testit
1

----------- example of strange behavior above -----------

Bug in bash? different from ksh, at any rate...

David Sastre's picture

On Sat, May 28, 2011 at 01:14:42AM -0700, Rick Thomas wrote:
>
> Can anybody explain this difference between the behavior of bash and
> ksh?
>
> When reading the man page, I would expect both of them to have the
> behavior exhibited by ksh.
> Why does bash seem to treat "return" like a single level "break" in
> this context?
>
> The "echo "$AA" | while read" is important context. If I change it
> to "for i in 0 1", return does as expected.
>
> If it's any help, changing "return" to "break 2" doesn't help. with
> bash, it still gives "1 1 1 1"
> while ksh still gives "1"
>
> I wonder if it has anything to do with "while read" causing a
> subshell to be created, and bash getting confused about the "return"
> inside of a subshell. If so, it's a bug in bash that ksh gets
> right, so it ought to be fixable.

I can't reproduce it:

$ cat strange.sh
function strange {
for j in 0 1 2 3
do
AA=' 1
2'
echo "$AA" | while read i
do
echo "$i"
return
done
done
}
echo $(strange)

$ bash ./strange.sh
1 1 1 1

$ ksh ./strange.sh
1 1 1 1

ii bash 4.1-3 The GNU Bourne Again SHell
ii mksh 39.3.20100725-1 MirBSD Korn Shell

Bug in bash? different from ksh, at any rate...

Rick Thomas's picture

On May 28, 2011, at 2:47 AM, David Sastre wrote:

> On Sat, May 28, 2011 at 01:14:42AM -0700, Rick Thomas wrote:
>>
>> Can anybody explain this difference between the behavior of bash and
>> ksh?
>>
>> When reading the man page, I would expect both of them to have the
>> behavior exhibited by ksh.
>> Why does bash seem to treat "return" like a single level "break" in
>> this context?
>>
>> The "echo "$AA" | while read" is important context. If I change it
>> to "for i in 0 1", return does as expected.
>>
>> If it's any help, changing "return" to "break 2" doesn't help. with
>> bash, it still gives "1 1 1 1"
>> while ksh still gives "1"
>>
>> I wonder if it has anything to do with "while read" causing a
>> subshell to be created, and bash getting confused about the "return"
>> inside of a subshell. If so, it's a bug in bash that ksh gets
>> right, so it ought to be fixable.
>
> I can't reproduce it:
>
> $ cat strange.sh
> function strange {
> for j in 0 1 2 3
> do
> AA=' 1
> 2'
> echo "$AA" | while read i
> do
> echo "$i"
> return
> done
> done
> }
> echo $(strange)
>
> $ bash ./strange.sh
> 1 1 1 1
>
> $ ksh ./strange.sh
> 1 1 1 1
>
> ii bash 4.1-3 The GNU Bourne Again SHell
> ii mksh 39.3.20100725-1 MirBSD Korn Shell
>

Bug in bash? different from ksh, at any rate...

Sven Joachim's picture

On 2011-05-28 10:14 +0200, Rick Thomas wrote:

> Can anybody explain this difference between the behavior of bash and
> ksh?

It depends on whether the shell starts a subshell for (compound)
commands in pipelines.

> When reading the man page, I would expect both of them to have the
> behavior exhibited by ksh.
> Why does bash seem to treat "return" like a single level "break" in
> this context?
>
> The "echo "$AA" | while read" is important context. If I change it to
> "for i in 0 1", return does as expected.

Actually, the pipeline is the most important. You can achieve the same
with a simpler script:

--88---
strange () {
for j in 0 1 2 3
do
: | { echo 1;return; }
done
}
echo $(strange)
--88---

> I wonder if it has anything to do with "while read" causing a subshell
> to be created,

Not exactly, it's the pipeline that causes creation of the subshell.

> and bash getting confused about the "return" inside of
> a subshell.

It does not get confused; as you can see, the subshell properly returns.

> If so, it's a bug in bash that ksh gets right, so it
> ought to be fixable.

There is no wrong or right here, since the susv3 specification is rather
vague:

,----
| Additionally, each command of a multi-command pipeline is in a subshell
| environment; as an extension, however, any or all commands in a pipeline
| may be executed in the current environment.
`----

So bash implements the default, while ksh implements the extension.
Having an option in bash to control the behavior would be nice, however.

See also the following blog entry:
http://backreference.org/2010/10/23/on-pipes-subshells-and-descriptors/.

Sven