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. Reference: /n/sources/patch/maybe/rc-fn-pipe-redir Date: Tue Sep 8 03:10:02 CES 2009 Signed-off-by: mt@ib.wmipf.de --- /sys/src/cmd/rc/pcmd.c Tue Sep 8 03:09:50 2009 +++ /sys/src/cmd/rc/pcmd.c Tue Sep 8 03:09:47 2009 @@ -135,7 +135,7 @@ pfmt(f, " %t", c2); break; case PIPE: - pfmt(f, "%t|", c0); + pfmt(f, c0->type==BRACE? "%t|": "{%t}|", c0); if(t->fd1==0){ if(t->fd0!=1) pfmt(f, "[%d]", t->fd0);