Re: Loops and pipes

Philippe Altherr <[email protected]> Tue, 4 Aug 2026 17:11:25 +0200
Newsgroups gmane.comp.shells.zsh.devel
Message-ID <CAGdYchtnz_ti5BSmyUFGQr2y3UYE5OCAi6PE9+nsh==rHbf4CQ@mail.gmail.com>
--00000000000039ff5406583a1242
Content-Type: multipart/alternative; boundary="00000000000039ff5306583a1240"

--00000000000039ff5306583a1240
Content-Type: text/plain; charset="UTF-8"

>
> Making it an error is quite simple:
>
> diff --git a/Src/exec.c b/Src/exec.c
> index 5f849db63..2e6684c96 100644
> --- a/Src/exec.c
> +++ b/Src/exec.c
> @@ -1258,6 +1258,7 @@ entersubsh(int flags, struct entersubsh_ret *retp)
>         clearjobtab(monitor);
>      get_usage();
>      forklevel = locallevel;
> +    loops = 0;
>  }
>
>  /* execute a string */
>

That works but for break/continue statements that are in a subshell of
their first enclosing loop it produces rather confusing error messages
stating that there are no loops. Here is a patch that avoids that:

- Forbid break/continue in subshells
<https://github.com/zsh-users/zsh/compare/master...paltherr:zsh:no-loop-control-from-subshell>

And here is a further patch that also checks that the break/continue
statements don't escape past the available loops:

- Forbid escaping past all enclosing loops in the same subshell
<https://github.com/paltherr/zsh/compare/forbid-escaping-past-all-loops-start...paltherr:zsh:forbid-escaping-past-all-loops>

The description of "continue n" states that it breaks out of n-1 loops and
resumes the nth loop but if there are m<n loops then it behaves as
"continue m", which is rather unexpected. The second patch avoids that by
making "continue n" (as well as "break n") illegal if n is greater than the
number of enclosing loops (started in the same subshell as the break/continue
statement).

Philippe

--00000000000039ff5306583a1240
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div class=3D"gmail_quote gmail_quote_container"><blockquo=
te class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px =
solid rgb(204,204,204);padding-left:1ex">Making it an error is quite simple=
:<br>
<br>
diff --git a/Src/exec.c b/Src/exec.c<br>
index 5f849db63..2e6684c96 100644<br>
--- a/Src/exec.c<br>
+++ b/Src/exec.c<br>
@@ -1258,6 +1258,7 @@ entersubsh(int flags, struct entersubsh_ret *retp)<br=
>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 clearjobtab(monitor);<br>
=C2=A0 =C2=A0 =C2=A0get_usage();<br>
=C2=A0 =C2=A0 =C2=A0forklevel =3D locallevel;<br>
+=C2=A0 =C2=A0 loops =3D 0;<br>
=C2=A0}<br>
<br>
=C2=A0/* execute a string */<br></blockquote><div><br></div><div>That works=
 but=C2=A0<span style=3D"background-color:transparent">for break/continue s=
tatements that are in a subshell of their first enclosing loop it produces=
=C2=A0</span><span style=3D"background-color:transparent">rather confusing =
error messages stating that there are no loops. Here is a patch that avoids=
 that:</span></div><div><span style=3D"background-color:transparent"><br></=
span></div><div>- <a href=3D"https://github.com/zsh-users/zsh/compare/maste=
r...paltherr:zsh:no-loop-control-from-subshell">Forbid break/continue in su=
bshells</a><span style=3D"background-color:transparent"></span></div><div><=
br></div><div>And here is a further patch that also checks that the=C2=A0<s=
pan style=3D"background-color:transparent">break/continue statements don&#3=
9;t escape past the available loops:</span></div><div><span style=3D"backgr=
ound-color:transparent"><br></span></div><div>- <a href=3D"https://github.c=
om/paltherr/zsh/compare/forbid-escaping-past-all-loops-start...paltherr:zsh=
:forbid-escaping-past-all-loops">Forbid escaping past all enclosing loops i=
n the same subshell</a><span style=3D"background-color:transparent"></span>=
</div><div><br></div><div>The description of &quot;continue n&quot; states =
that it breaks out of n-1 loops and resumes the nth loop but if there are m=
&lt;n loops then it behaves as &quot;continue m&quot;, which is rather unex=
pected. The second patch avoids that by making=C2=A0<span style=3D"backgrou=
nd-color:transparent">&quot;continue n&quot; (as well as &quot;break n&quot=
;) illegal if n is greater than the number of enclosing loops (started in t=
he same subshell as the=C2=A0</span>break/continue statement<span style=3D"=
background-color:transparent">).</span></div><div><br></div><div>Philippe</=
div><div><br></div></div></div>

--00000000000039ff5306583a1240--
--00000000000039ff5406583a1242
Content-Type: text/plain; charset="US-ASCII"; name="no-loop-control-from-subshell.txt"
Content-Disposition: attachment; 
	filename="no-loop-control-from-subshell.txt"
Content-Transfer-Encoding: base64
Content-ID: <f_msesp7nn0>
X-Attachment-Id: f_msesp7nn0

ZGlmZiAtLWdpdCBhL1NyYy9idWlsdGluLmMgYi9TcmMvYnVpbHRpbi5jCmluZGV4IGUzNWQ3ZmUy
Yy4uMTBjNjRkM2M4IDEwMDY0NAotLS0gYS9TcmMvYnVpbHRpbi5jCisrKyBiL1NyYy9idWlsdGlu
LmMKQEAgLTU4MTQsMjQgKzU4MTQsMjIgQEAgYmluX2JyZWFrKGNoYXIgKm5hbWUsIGNoYXIgKiph
cmd2LCBVTlVTRUQoT3B0aW9ucyBvcHMpLCBpbnQgZnVuYykKIAludW1wID0gMTsKICAgICB9CiAK
LSAgICBpZiAobnVtcCA+IDAgJiYgKGZ1bmMgPT0gQklOX0NPTlRJTlVFIHx8IGZ1bmMgPT0gQklO
X0JSRUFLKSAmJiBudW0gPD0gMCkgewotCXplcnJuYW0obmFtZSwgImFyZ3VtZW50IGlzIG5vdCBw
b3NpdGl2ZTogJWQiLCBudW0pOwotCXJldHVybiAxOwotICAgIH0KLQogICAgIHN3aXRjaCAoZnVu
YykgewogICAgIGNhc2UgQklOX0NPTlRJTlVFOgotCWlmICghbG9vcHMpIHsgICAvKiBjb250aW51
ZSBpcyBvbmx5IHBlcm1pdHRlZCBpbiBsb29wcyAqLwotCSAgICB6ZXJybmFtKG5hbWUsICJub3Qg
aW4gd2hpbGUsIHVudGlsLCBzZWxlY3QsIG9yIHJlcGVhdCBsb29wIik7CisgICAgY2FzZSBCSU5f
QlJFQUs6CisJbnVtID0gbnVtcCA/IG51bSA6IDE7CisJaWYgKG51bSA8PSAwKSB7CisJICAgIHpl
cnJuYW0obmFtZSwgImFyZ3VtZW50IGlzIG5vdCBwb3NpdGl2ZTogJWQiLCBudW0pOwogCSAgICBy
ZXR1cm4gMTsKIAl9Ci0JY29udGZsYWcgPSAxOyAvKiBGQUxMVEhST1VHSCAqLwotICAgIGNhc2Ug
QklOX0JSRUFLOgotCWlmICghbG9vcHMpIHsgICAvKiBicmVhayBpcyBvbmx5IHBlcm1pdHRlZCBp
biBsb29wcyAqLwotCSAgICB6ZXJybmFtKG5hbWUsICJub3QgaW4gd2hpbGUsIHVudGlsLCBzZWxl
Y3QsIG9yIHJlcGVhdCBsb29wIik7CisJaWYgKCFsb29wcykgeyAgIC8qIGJyZWFrL2NvbnRpbnVl
IG9ubHkgcGVybWl0dGVkIGluIGxvb3BzICovCisJICAgIHplcnJuYW0obmFtZSwgYW5jZXN0b3Jf
bG9vcHMKKwkJICAgID8gIm5vdCBpbiBzYW1lIHN1YnNoZWxsIGFzIGZpcnN0IGVuY2xvc2luZyBs
b29wIgorCQkgICAgOiAibm90IGluIGZvciwgd2hpbGUsIHVudGlsLCBzZWxlY3QsIG9yIHJlcGVh
dCBsb29wIik7CiAJICAgIHJldHVybiAxOwogCX0KLQlicmVha3MgPSBudW1wID8gbWluaW11bShu
dW0sbG9vcHMpIDogMTsKKwljb250ZmxhZyA9IGZ1bmMgPT0gQklOX0NPTlRJTlVFOworCWJyZWFr
cyA9IG1pbmltdW0obnVtLCBsb29wcyk7CiAJYnJlYWs7CiAgICAgY2FzZSBCSU5fUkVUVVJOOgog
CWlmICgoaXNzZXQoSU5URVJBQ1RJVkUpICYmIGlzc2V0KFNISU5TVERJTikpCmRpZmYgLS1naXQg
YS9TcmMvZXhlYy5jIGIvU3JjL2V4ZWMuYwppbmRleCA1Zjg0OWRiNjMuLjk0ZjFiNzM1YyAxMDA2
NDQKLS0tIGEvU3JjL2V4ZWMuYworKysgYi9TcmMvZXhlYy5jCkBAIC0xMjU4LDYgKzEyNTgsOCBA
QCBlbnRlcnN1YnNoKGludCBmbGFncywgc3RydWN0IGVudGVyc3Vic2hfcmV0ICpyZXRwKQogCWNs
ZWFyam9idGFiKG1vbml0b3IpOwogICAgIGdldF91c2FnZSgpOwogICAgIGZvcmtsZXZlbCA9IGxv
Y2FsbGV2ZWw7CisgICAgYW5jZXN0b3JfbG9vcHMgKz0gbG9vcHM7CisgICAgbG9vcHMgPSAwOwog
fQogCiAvKiBleGVjdXRlIGEgc3RyaW5nICovCmRpZmYgLS1naXQgYS9TcmMvaW5pdC5jIGIvU3Jj
L2luaXQuYwppbmRleCBkMmI5N2RhZmYuLmM1ZTkxNWJiMSAxMDA2NDQKLS0tIGEvU3JjL2luaXQu
YworKysgYi9TcmMvaW5pdC5jCkBAIC0xMzI1LDcgKzEzMjUsNyBAQCBzZXR1cHZhbHMoY2hhciAq
Y21kLCBjaGFyICpydW5zY3JpcHQsIGNoYXIgKnpzaF9uYW1lKQogICAgIH0KICNlbmRpZgogCi0g
ICAgYnJlYWtzID0gbG9vcHMgPSAwOworICAgIGJyZWFrcyA9IGNvbnRmbGFnID0gbG9vcHMgPSBh
bmNlc3Rvcl9sb29wcyA9IDA7CiAgICAgbGFzdG1haWxjaGVjayA9IHptb25vdGltZShOVUxMKTsK
ICAgICBsb2NhbGxldmVsID0gc291cmNlbGV2ZWwgPSAwOwogICAgIHNmY29udGV4dCA9IFNGQ19O
T05FOwpkaWZmIC0tZ2l0IGEvU3JjL2xvb3AuYyBiL1NyYy9sb29wLmMKaW5kZXggMzUxZWRkZTg5
Li42NmRhZDA1ZjggMTAwNjQ0Ci0tLSBhL1NyYy9sb29wLmMKKysrIGIvU3JjL2xvb3AuYwpAQCAt
MzAsMTggKzMwLDIzIEBACiAjaW5jbHVkZSAienNoLm1kaCIKICNpbmNsdWRlICJsb29wLnBybyIK
IAotLyogIyBvZiBuZXN0ZWQgbG9vcHMgd2UgYXJlIGluICovCi0gCisvKiAjIG9mIG5lc3RlZCBs
b29wcyB3ZSBhcmUgaW4gc3RhcnRlZCBpbiBhbmNlc3RvciBzdWJzaGVsbHMgKi8KKworLyoqLwor
aW50IGFuY2VzdG9yX2xvb3BzOworCisvKiAjIG9mIG5lc3RlZCBsb29wcyB3ZSBhcmUgaW4gc3Rh
cnRlZCBpbiB0aGUgY3VycmVudCBzdWJzaGVsbCAqLworCiAvKiovCiBpbnQgbG9vcHM7Ci0gCi0v
KiAjIG9mIGNvbnRpbnVlIGxldmVscyAqLwotIAorCisvKiB3aGV0aGVyIHRvIGNvbnRpbnVlIGlu
c3RlYWQgb2YgYnJlYWsgb24gdGhlIGxhc3QgYnJlYWsgbGV2ZWwgKi8KKwogLyoqLwogbW9kX2V4
cG9ydCBpbnQgY29udGZsYWc7Ci0gCisKIC8qICMgb2YgYnJlYWsgbGV2ZWxzICovCi0gCisKIC8q
Ki8KIG1vZF9leHBvcnQgdm9sYXRpbGUgaW50IGJyZWFrczsKIApkaWZmIC0tZ2l0IGEvVGVzdC9B
MDdjb250cm9sLnp0c3QgYi9UZXN0L0EwN2NvbnRyb2wuenRzdAppbmRleCBiMWEyNDg3MzIuLmNm
NzBkNDZmZSAxMDA2NDQKLS0tIGEvVGVzdC9BMDdjb250cm9sLnp0c3QKKysrIGIvVGVzdC9BMDdj
b250cm9sLnp0c3QKQEAgLTI4LDcgKzI4LDE4IEBACiAgIH0KICAgZm4nCiAxOmNvbnRpbnVlIG91
dHNpZGUgbG9vcAotP2ZuOmNvbnRpbnVlOjE6IG5vdCBpbiB3aGlsZSwgdW50aWwsIHNlbGVjdCwg
b3IgcmVwZWF0IGxvb3AKKz9mbjpjb250aW51ZToxOiBub3QgaW4gZm9yLCB3aGlsZSwgdW50aWws
IHNlbGVjdCwgb3IgcmVwZWF0IGxvb3AKKworICBmb3IgeCBpbiBhIGIgYzsgZG8KKyAgICAoIGVj
aG8gJHg6YmVmb3JlOyBjb250aW51ZSAyPiYxOyBlY2hvICR4OmFmdGVyICkKKyAgZG9uZQorMTpj
b250aW51ZSBpbiBzdWJzaGVsbAorPmE6YmVmb3JlCis+KGV2YWwpOmNvbnRpbnVlOjI6IG5vdCBp
biBzYW1lIHN1YnNoZWxsIGFzIGZpcnN0IGVuY2xvc2luZyBsb29wCis+YjpiZWZvcmUKKz4oZXZh
bCk6Y29udGludWU6Mjogbm90IGluIHNhbWUgc3Vic2hlbGwgYXMgZmlyc3QgZW5jbG9zaW5nIGxv
b3AKKz5jOmJlZm9yZQorPihldmFsKTpjb250aW51ZToyOiBub3QgaW4gc2FtZSBzdWJzaGVsbCBh
cyBmaXJzdCBlbmNsb3NpbmcgbG9vcAogCiAgIGZvciBvdXRlciBpbiAwIDEgMiAzOyBkbwogICAg
IHByaW50IG91dGVyICRvdXRlcgo=
--00000000000039ff5406583a1242
Content-Type: text/plain; charset="US-ASCII"; name="forbid-escaping-past-all-loops.txt"
Content-Disposition: attachment; 
	filename="forbid-escaping-past-all-loops.txt"
Content-Transfer-Encoding: base64
Content-ID: <f_msesphs61>
X-Attachment-Id: f_msesphs61

ZGlmZiAtLWdpdCBhL1NyYy9idWlsdGluLmMgYi9TcmMvYnVpbHRpbi5jCmluZGV4IDEwYzY0ZDNj
OC4uNDllZmZiMjJiIDEwMDY0NAotLS0gYS9TcmMvYnVpbHRpbi5jCisrKyBiL1NyYy9idWlsdGlu
LmMKQEAgLTU4MjIsMTAgKzU4MjIsMjAgQEAgYmluX2JyZWFrKGNoYXIgKm5hbWUsIGNoYXIgKiph
cmd2LCBVTlVTRUQoT3B0aW9ucyBvcHMpLCBpbnQgZnVuYykKIAkgICAgemVycm5hbShuYW1lLCAi
YXJndW1lbnQgaXMgbm90IHBvc2l0aXZlOiAlZCIsIG51bSk7CiAJICAgIHJldHVybiAxOwogCX0K
LQlpZiAoIWxvb3BzKSB7ICAgLyogYnJlYWsvY29udGludWUgb25seSBwZXJtaXR0ZWQgaW4gbG9v
cHMgKi8KLQkgICAgemVycm5hbShuYW1lLCBhbmNlc3Rvcl9sb29wcwotCQkgICAgPyAibm90IGlu
IHNhbWUgc3Vic2hlbGwgYXMgZmlyc3QgZW5jbG9zaW5nIGxvb3AiCi0JCSAgICA6ICJub3QgaW4g
Zm9yLCB3aGlsZSwgdW50aWwsIHNlbGVjdCwgb3IgcmVwZWF0IGxvb3AiKTsKKwlpZiAobnVtID4g
bG9vcHMpIHsgICAvKiBicmVhay9jb250aW51ZSBvbmx5IHBlcm1pdHRlZCBpbiBsb29wcyAqLwor
CSAgICBpZiAoIWxvb3BzICYmICFhbmNlc3Rvcl9sb29wcykKKwkJemVycm5hbShuYW1lLAorCQkJ
Im5vdCBpbiBmb3IsIHdoaWxlLCB1bnRpbCwgc2VsZWN0LCBvciByZXBlYXQgbG9vcCIpOworCSAg
ICBlbHNlIGlmIChudW0gPiBsb29wcyArIGFuY2VzdG9yX2xvb3BzKQorCQl6ZXJybmFtKG5hbWUs
CisJCQkibm90IGluICVkIGZvciwgd2hpbGUsIHVudGlsLCBzZWxlY3QsIG9yIHJlcGVhdCBsb29w
cyIsCisJCQludW0pOworCSAgICBlbHNlIGlmICghbG9vcHMpCisJCXplcnJuYW0obmFtZSwgIm5v
dCBpbiBzYW1lIHN1YnNoZWxsIGFzIGZpcnN0IGVuY2xvc2luZyBsb29wIik7CisJICAgIGVsc2UK
KwkJemVycm5hbShuYW1lLAorCQkJIm5vdCBpbiBzYW1lIHN1YnNoZWxsIGFzIGZpcnN0ICVkIGVu
Y2xvc2luZyBsb29wcyIsCisJCQludW0pOwogCSAgICByZXR1cm4gMTsKIAl9CiAJY29udGZsYWcg
PSBmdW5jID09IEJJTl9DT05USU5VRTsKZGlmZiAtLWdpdCBhL1Rlc3QvQTA3Y29udHJvbC56dHN0
IGIvVGVzdC9BMDdjb250cm9sLnp0c3QKaW5kZXggY2Y3MGQ0NmZlLi5hZGI2NzZmMjMgMTAwNjQ0
Ci0tLSBhL1Rlc3QvQTA3Y29udHJvbC56dHN0CisrKyBiL1Rlc3QvQTA3Y29udHJvbC56dHN0CkBA
IC0zMCw2ICszMCwyMSBAQAogMTpjb250aW51ZSBvdXRzaWRlIGxvb3AKID9mbjpjb250aW51ZTox
OiBub3QgaW4gZm9yLCB3aGlsZSwgdW50aWwsIHNlbGVjdCwgb3IgcmVwZWF0IGxvb3AKIAorICAk
WlRTVF90ZXN0ZGlyLy4uL1NyYy96c2ggLWZjICcKKyAgICBmb3IgeCBpbiBhIGIgYzsgZG8KKyAg
ICAgIGZvciB5IGluIGQgZSBmOyBkbworICAgICAgICBlY2hvICIkeCR5OmJlZm9yZSIKKyAgICAg
ICAgY29udGludWUgMworICAgICAgICBlY2hvICIkeCR5OmFmdGVyIgorICAgICAgZG9uZQorICAg
ICAgZWNobyAiJHgtOmFmdGVyIgorICAgIGRvbmUKKyAgICBlY2hvICItLTphZnRlciIKKyAgJwor
MTpjb250aW51ZSBiZXlvbmQgYWxsIGVuY2xvc2luZyBsb29wcworPmFkOmJlZm9yZQorP3pzaDpj
b250aW51ZTo1OiBub3QgaW4gMyBmb3IsIHdoaWxlLCB1bnRpbCwgc2VsZWN0LCBvciByZXBlYXQg
bG9vcHMKKwogICBmb3IgeCBpbiBhIGIgYzsgZG8KICAgICAoIGVjaG8gJHg6YmVmb3JlOyBjb250
aW51ZSAyPiYxOyBlY2hvICR4OmFmdGVyICkKICAgZG9uZQpAQCAtNDEsNiArNTYsMzEgQEAKID5j
OmJlZm9yZQogPihldmFsKTpjb250aW51ZToyOiBub3QgaW4gc2FtZSBzdWJzaGVsbCBhcyBmaXJz
dCBlbmNsb3NpbmcgbG9vcAogCisgIGZvciB4IGluIGEgYiBjOyBkbworICAgICgKKyAgICAgIGZv
ciB5IGluIGQgZSBmOyBkbworICAgICAgICBlY2hvICIkeCR5OmJlZm9yZSIKKyAgICAgICAgY29u
dGludWUgMiAyPiYxCisgICAgICAgIGVjaG8gIiR4JHk6YWZ0ZXIiCisgICAgICBkb25lCisgICAg
ICBlY2hvICIkeC06YWZ0ZXIxIgorICAgICkKKyAgICBlY2hvICIkeC06YWZ0ZXIyIgorICBkb25l
CisgIGVjaG8gIi0tOmFmdGVyIgorMDpjb250aW51ZSBiZXlvbmQgYWxsIGVuY2xvc2luZyBsb29w
cworPmFkOmJlZm9yZQorPihldmFsKTpjb250aW51ZTo1OiBub3QgaW4gc2FtZSBzdWJzaGVsbCBh
cyBmaXJzdCAyIGVuY2xvc2luZyBsb29wcworPmEtOmFmdGVyMgorPmJkOmJlZm9yZQorPihldmFs
KTpjb250aW51ZTo1OiBub3QgaW4gc2FtZSBzdWJzaGVsbCBhcyBmaXJzdCAyIGVuY2xvc2luZyBs
b29wcworPmItOmFmdGVyMgorPmNkOmJlZm9yZQorPihldmFsKTpjb250aW51ZTo1OiBub3QgaW4g
c2FtZSBzdWJzaGVsbCBhcyBmaXJzdCAyIGVuY2xvc2luZyBsb29wcworPmMtOmFmdGVyMgorPi0t
OmFmdGVyCisKKwogICBmb3Igb3V0ZXIgaW4gMCAxIDIgMzsgZG8KICAgICBwcmludCBvdXRlciAk
b3V0ZXIKICAgICBmb3IgaW5uZXIgaW4gMCAxIDIgMzsgZG8K
--00000000000039ff5406583a1242--