Plan 9 from Bell Labs’s /usr/web/sources/patch/maybe/rc-fn-pipe-redir/readme

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


This patch will fix an issue with redirections in
pipelines within rc functions.
--

If inside an rc function a pipeline is used that
contains a redirection, this might not work as
expected in (sub) shells that import the function
from environment.

For example, at an rc prompt, type:

	fn f{
		echo -n $pid:
		echo >/dev/null | echo -n wor
		{echo failed >[1=2]} >[2=1] | sed 's/failed/ks!/'
	}

	f	# should work

	rc -c f	# will fail

First `f' is executed by the shell which parsed
function f.  Then f is exported to the rc
subshell, imported by it, and executed.
Here the ">/dev/null", or ">[2=1]" sequences
will not work as expected.

What happens is that the meaning of the
redirections change while the function definition
is processed.  When the function is exported by
addenv(), a string fn[pc-1].s is printed into
/env/fn#...

This string got constructed by emits(fnstr(...))
in /sys/src/cmd/rc/code.c:173, which calls
pfmt("%t"), which will put together the string
calling pcmd() as needed.  In other words, the
`tree' structure is translated back into a string.

Since the redirections come earlier in the tree,
they will be printed first, so when the function
is translated into a string, it will look like

	...
	>/dev/null  echo | ...
	>[2=1]  {echo failed >[1=2]}  | ...

Note that the redirections now come first, and
have got a different meaning: they will apply to
the whole pipeline, not to the first command only.
This is because of the definitions in syn.y:
	|	cmd PIPE cmd
	|	redir cmd
For a redirection at the beginning of a line
the whole pipeline looks like one `cmd'.

If a subshell later imports f from /env/fn#f, it
obviously will get a function different from the
initially defined one.

Two probable solutions came to my mind,

1.	in pcmd(), for the cases DUP and REDIR
	change the order "c1" and the redirection
	sequences are printed, so that the example
	lines would be exported as they were
	defined:
		echo >/dev/null | ...
		{echo failed >[1=2]} >[2=1] | ...
	It turned out that this is not so easy, as
	in case of multiple redirections they
	would be produced in reversed, i.e.
	wrong, order.

2.	In "case PIPE:", enclose %t within braces,
	so that a pipeline
		cmd >/dev/null | cmd2
	would be exported as
		{>/dev/null cmd} | cmd2

	To avoid an increasing number of braces
	growing with each subshell started, it
	could be tested whether there is already a
	brace present, like this:

	case PIPE:
	-		pfmt(f, "%t|", c0);
	+		pfmt(f, c0->type==BRACE? "%t|": "{%t}|", c0);


#1 did not work for me, #2 produces the expected
results, as can be checked with the initial example.

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.