* Is it possible to capture stdout and stderr to separate variables in Zsh?
@ 2012-03-06 8:09 Nikolai Weibull
2012-03-06 17:16 ` Philippe Troin
2012-08-31 0:40 ` Paul Maisano
0 siblings, 2 replies; 13+ messages in thread
From: Nikolai Weibull @ 2012-03-06 8:09 UTC (permalink / raw)
To: Zsh Users
Hi!
Is it possible to capture stdout and stderr to separate variables in Zsh?
I understand that it’s not possible in sh, but I was wondering if any
of Zsh’s additions in the redirection area would allow for such a
separation.
Thanks!
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Is it possible to capture stdout and stderr to separate variables in Zsh?
2012-03-06 8:09 Is it possible to capture stdout and stderr to separate variables in Zsh? Nikolai Weibull
@ 2012-03-06 17:16 ` Philippe Troin
2012-03-07 7:01 ` Bart Schaefer
2012-08-31 0:40 ` Paul Maisano
1 sibling, 1 reply; 13+ messages in thread
From: Philippe Troin @ 2012-03-06 17:16 UTC (permalink / raw)
To: Nikolai Weibull; +Cc: Zsh Users
On Tue, 2012-03-06 at 09:09 +0100, Nikolai Weibull wrote:
> Is it possible to capture stdout and stderr to separate variables in Zsh?
>
> I understand that it’s not possible in sh, but I was wondering if any
> of Zsh’s additions in the redirection area would allow for such a
> separation.
All I can think of is:
coproc cat &
pid=$!
stdout="$( ( print "printed on stdout"; print -u 2 "printer on stderr" ) 2>&p )"
sleep 1
kill "$pid"
stderr="$(cat <&p)"
print "stdout=\"$stdout\""
print "stderr=\"$stderr\""
You'll notice the very ugly sleep+kill hack I had to use as I could not
find how you can close a coprocess's standard input cleanly. Removing
the sleep+kill makes the cat <&p hang forever.
Of course this solution will hang if more than a buffer-full is printed
on stderr. You can play tricks with dd by providing a bigger buffer, as
in:
coproc dd obs=1M &
But in the end it's a losing game. You might as well use a temporary
file for one of the output streams.
A completely different solution could involve the tcp zsh module which
can multiplex many streams with tcp_expect. But that's probably too
involved for this problem.
Phil.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Is it possible to capture stdout and stderr to separate variables in Zsh?
2012-03-06 17:16 ` Philippe Troin
@ 2012-03-07 7:01 ` Bart Schaefer
2012-03-07 9:26 ` Nikolai Weibull
` (2 more replies)
0 siblings, 3 replies; 13+ messages in thread
From: Bart Schaefer @ 2012-03-07 7:01 UTC (permalink / raw)
To: Zsh Users
On Mar 6, 9:16am, Philippe Troin wrote:
}
} On Tue, 2012-03-06 at 09:09 +0100, Nikolai Weibull wrote:
} > Is it possible to capture stdout and stderr to separate variables in Zsh?
}
} All I can think of is:
}
} coproc cat &
} pid=$!
} stdout="$( ( print "printed on stdout"; print -u 2 "printer on stderr" ) 2>&p )"
} sleep 1
} kill "$pid"
} stderr="$(cat <&p)"
}
} You'll notice the very ugly sleep+kill hack I had to use as I could not
} find how you can close a coprocess's standard input cleanly. Removing
} the sleep+kill makes the cat <&p hang forever.
You need this: http://www.zsh.org/mla/users/2011/msg00095.html :-)
} A completely different solution could involve the tcp zsh module which
} can multiplex many streams with tcp_expect. But that's probably too
} involved for this problem.
You might also be able to do something with the zsh/zselect module, but
just use a temp file. That solution works in bash, too.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Is it possible to capture stdout and stderr to separate variables in Zsh?
2012-03-07 7:01 ` Bart Schaefer
@ 2012-03-07 9:26 ` Nikolai Weibull
2012-03-08 14:53 ` Bart Schaefer
2012-09-10 6:16 ` Han Pingtian
2012-03-07 19:37 ` Philippe Troin
2012-09-01 11:59 ` Han Pingtian
2 siblings, 2 replies; 13+ messages in thread
From: Nikolai Weibull @ 2012-03-07 9:26 UTC (permalink / raw)
To: Bart Schaefer; +Cc: Zsh Users
On Wed, Mar 7, 2012 at 08:01, Bart Schaefer <schaefer@brasslantern.com> wrote:
> } On Tue, 2012-03-06 at 09:09 +0100, Nikolai Weibull wrote:
> } > Is it possible to capture stdout and stderr to separate variables in Zsh?
> You might also be able to do something with the zsh/zselect module, but
> just use a temp file. That solution works in bash, too.
Invoking two additional commands (mktemp and rm) is prohibitively
expensive on Cygwin for my use case. I used the following solution
instead:
outs=("${(@0):-"$({ out=$(x) } 2>&1; print $'\0'$out$'\0'$status)"}")
The indexes into outs are reversed in regard to the file descriptors,
but that’s not a big deal.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Is it possible to capture stdout and stderr to separate variables in Zsh?
2012-03-07 7:01 ` Bart Schaefer
2012-03-07 9:26 ` Nikolai Weibull
@ 2012-03-07 19:37 ` Philippe Troin
2012-03-08 4:56 ` Bart Schaefer
2012-09-01 11:59 ` Han Pingtian
2 siblings, 1 reply; 13+ messages in thread
From: Philippe Troin @ 2012-03-07 19:37 UTC (permalink / raw)
To: Zsh Users
On Tue, 2012-03-06 at 23:01 -0800, Bart Schaefer wrote:
> On Mar 6, 9:16am, Philippe Troin wrote:
> }
> } On Tue, 2012-03-06 at 09:09 +0100, Nikolai Weibull wrote:
> } > Is it possible to capture stdout and stderr to separate variables in Zsh?
> }
> } All I can think of is:
> }
> } coproc cat &
> } pid=$!
> } stdout="$( ( print "printed on stdout"; print -u 2 "printer on stderr" ) 2>&p )"
> } sleep 1
> } kill "$pid"
> } stderr="$(cat <&p)"
> }
> } You'll notice the very ugly sleep+kill hack I had to use as I could not
> } find how you can close a coprocess's standard input cleanly. Removing
> } the sleep+kill makes the cat <&p hang forever.
>
> You need this: http://www.zsh.org/mla/users/2011/msg00095.html :-)
I didn't see anything in there that could suppress the sleep+kill.
> } A completely different solution could involve the tcp zsh module which
> } can multiplex many streams with tcp_expect. But that's probably too
> } involved for this problem.
>
> You might also be able to do something with the zsh/zselect module, but
> just use a temp file. That solution works in bash, too.
I like Nikolai's solution best, except that it's somewhat cryptic and it
munges NULs and trailing newlines.
outs=("${(@0):-"$({ out=$(x) } 2>&1; print $'\0'$out$'\0'$status)"}")
Phil.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Is it possible to capture stdout and stderr to separate variables in Zsh?
2012-03-07 19:37 ` Philippe Troin
@ 2012-03-08 4:56 ` Bart Schaefer
0 siblings, 0 replies; 13+ messages in thread
From: Bart Schaefer @ 2012-03-08 4:56 UTC (permalink / raw)
To: Zsh Users
On Mar 7, 11:37am, Philippe Troin wrote:
}
} > } coproc cat &
} > } pid=$!
} > } stdout="$( ( print "printed on stdout"; print -u 2 "printer on stderr" ) 2>&p )"
} > } sleep 1
} > } kill "$pid"
} > } stderr="$(cat <&p)"
} >
} > You need this: http://www.zsh.org/mla/users/2011/msg00095.html :-)
}
} I didn't see anything in there that could suppress the sleep+kill.
Look at the part subtitled "Where might I go wrong with coproc?" ... it
doesn't answer the whole problem, but it tells you how to cleanly close
the descriptors. The full solution is more like:
coproc cat &
exec {p}<&p # Copy the <&p descriptor
stdout="$( ( print "printed on stdout";
print -u 2 "printed on stderr") 2>&p )"
coproc exit # Close both <&p and >&p descriptors
stderr="$(cat <&$p)" # Read from copy descriptor
exec {p}<&- # Close the copy (optional)
I also dug this up: http://www.zsh.org/mla/workers/2000/msg03684.html
but that predates the fancy {p}<&p syntax.
} I like Nikolai's solution best, except that it's somewhat cryptic
Yeah, I may have some thoughts on that one, too.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Is it possible to capture stdout and stderr to separate variables in Zsh?
2012-03-07 9:26 ` Nikolai Weibull
@ 2012-03-08 14:53 ` Bart Schaefer
2012-03-30 7:15 ` Nikolai Weibull
2012-09-10 6:16 ` Han Pingtian
1 sibling, 1 reply; 13+ messages in thread
From: Bart Schaefer @ 2012-03-08 14:53 UTC (permalink / raw)
To: Zsh Users
On Mar 7, 10:26am, Nikolai Weibull wrote:
}
} outs=("${(@0):-"$({ out=$(x) } 2>&1; print $'\0'$out$'\0'$status)"}")
That's nice. You can solve the problem that Philippe mentioned with
loss of trailing newlines, by embedding one NUL in $out like so:
outs=("${(@0):-"$({ out="$(x; print -n $'\0')" } 2>&1;
print $'\0'$out$status)"}")
Then I sort of like the idea of making it into an associative array:
typeset -A outs
outs=(STDERR "${(@0):-"$({ out="$(x; print -n $'\0')" } 2>&1;
print $'\0'STDOUT$'\0'${out}STATUS$'\0'$status)"}")
print -r $outs[STDOUT]
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Is it possible to capture stdout and stderr to separate variables in Zsh?
2012-03-08 14:53 ` Bart Schaefer
@ 2012-03-30 7:15 ` Nikolai Weibull
2012-03-30 14:49 ` Bart Schaefer
0 siblings, 1 reply; 13+ messages in thread
From: Nikolai Weibull @ 2012-03-30 7:15 UTC (permalink / raw)
To: Bart Schaefer; +Cc: Zsh Users
On Thu, Mar 8, 2012 at 15:53, Bart Schaefer <schaefer@brasslantern.com> wrote:
> On Mar 7, 10:26am, Nikolai Weibull wrote:
> }
> } outs=("${(@0):-"$({ out=$(x) } 2>&1; print $'\0'$out$'\0'$status)"}")
>
> That's nice. You can solve the problem that Philippe mentioned with
> loss of trailing newlines, by embedding one NUL in $out like so:
>
> outs=("${(@0):-"$({ out="$(x; print -n $'\0')" } 2>&1;
> print $'\0'$out$status)"}")
That will, however, override the value of $status.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Is it possible to capture stdout and stderr to separate variables in Zsh?
2012-03-30 7:15 ` Nikolai Weibull
@ 2012-03-30 14:49 ` Bart Schaefer
0 siblings, 0 replies; 13+ messages in thread
From: Bart Schaefer @ 2012-03-30 14:49 UTC (permalink / raw)
To: Zsh Users
On Mar 30, 9:15am, Nikolai Weibull wrote:
} Subject: Re: Is it possible to capture stdout and stderr to separate varia
}
} On Thu, Mar 8, 2012 at 15:53, Bart Schaefer <schaefer@brasslantern.com> wrote:
} > On Mar 7, 10:26am, Nikolai Weibull wrote:
} > }
} > } outs=("${(@0):-"$({ out=$(x) } 2>&1; print $'\0'$out$'\0'$status)"}")
} >
} > That's nice. You can solve the problem that Philippe mentioned with
} > loss of trailing newlines, by embedding one NUL in $out like so:
} >
} > outs=("${(@0):-"$({ out="$(x; print -n $'\0')" } 2>&1;
} > print $'\0'$out$status)"}")
}
} That will, however, override the value of $status.
Indeed, good catch. You need to pull $status inside the $(...) too
(in which case the trailing newline doesn't matter any more):
outs=("${(@0):-"$({ out="$(x; print $'\0'$status)" } 2>&1;
print $'\0'$out)"}")
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Is it possible to capture stdout and stderr to separate variables in Zsh?
2012-03-06 8:09 Is it possible to capture stdout and stderr to separate variables in Zsh? Nikolai Weibull
2012-03-06 17:16 ` Philippe Troin
@ 2012-08-31 0:40 ` Paul Maisano
1 sibling, 0 replies; 13+ messages in thread
From: Paul Maisano @ 2012-08-31 0:40 UTC (permalink / raw)
To: zsh-users
Nikolai Weibull <now <at> bitwi.se> writes:
>
> Hi!
>
> Is it possible to capture stdout and stderr to separate variables in Zsh?
>
> I understand that it’s not possible in sh, but I was wondering if any
> of Zsh’s additions in the redirection area would allow for such a
> separation.
Try this:
var1=`cmd` 2>&1 | read var2
Now var1 contains stdout from cmd and var2 contains stderr!
It might work with other shells too.
Regards,
Paul Maisano
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Is it possible to capture stdout and stderr to separate variables in Zsh?
2012-03-07 7:01 ` Bart Schaefer
2012-03-07 9:26 ` Nikolai Weibull
2012-03-07 19:37 ` Philippe Troin
@ 2012-09-01 11:59 ` Han Pingtian
2012-09-09 19:18 ` Bart Schaefer
2 siblings, 1 reply; 13+ messages in thread
From: Han Pingtian @ 2012-09-01 11:59 UTC (permalink / raw)
To: zsh-users
On Tue, Mar 06, 2012 at 11:01:11PM -0800, Bart Schaefer wrote:
> On Mar 6, 9:16am, Philippe Troin wrote:
> }
> } On Tue, 2012-03-06 at 09:09 +0100, Nikolai Weibull wrote:
> } > Is it possible to capture stdout and stderr to separate variables in Zsh?
> }
> } All I can think of is:
> }
> } coproc cat &
> } pid=$!
> } stdout="$( ( print "printed on stdout"; print -u 2 "printer on stderr" ) 2>&p )"
> } sleep 1
> } kill "$pid"
> } stderr="$(cat <&p)"
> }
> } You'll notice the very ugly sleep+kill hack I had to use as I could not
> } find how you can close a coprocess's standard input cleanly. Removing
> } the sleep+kill makes the cat <&p hang forever.
>
> You need this: http://www.zsh.org/mla/users/2011/msg00095.html :-)
>
Hi,
I'm using zsh 5.0, but looks like still cannot close the prior coproc
with "coproc exit":
% coproc while read line;do print -r -- "$line:u";done
[1] 31518
% coproc exit
[2] 31519
%
[2] + done exit
% jobs
[1] + running while read line; do; print -r -- "$line:u"; done
%
or I'm missing something here?
Thanks.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Is it possible to capture stdout and stderr to separate variables in Zsh?
2012-09-01 11:59 ` Han Pingtian
@ 2012-09-09 19:18 ` Bart Schaefer
0 siblings, 0 replies; 13+ messages in thread
From: Bart Schaefer @ 2012-09-09 19:18 UTC (permalink / raw)
To: Han Pingtian, zsh-users
On Sep 1, 7:59pm, Han Pingtian wrote:
}
} I'm using zsh 5.0, but looks like still cannot close the prior coproc
} with "coproc exit":
}
} % coproc while read line;do print -r -- "$line:u";done
This is a bug/misfeature that I think I've mentioned before (possibly
only on zsh-workers) which affects built-in commands including loop
constructs.
The trouble is that zsh opens the coproc descriptors in the parent
shell (as it must) and marks them close-on-exec. It then forks for
the actual coprocess job and dups the coproc descriptors to the job's
stdin and stdout.
Then the bug happens: Because the coprocess is a built-in, there is
no exec, so the original coproc descriptors are never closed. This
leaves the coprocess "talking to itself":
zsh 17133 schaefer 0r FIFO 0,7 2256774 pipe
zsh 17133 schaefer 1w FIFO 0,7 2256773 pipe
zsh 17133 schaefer 2u CHR 136,2 4 /dev/pts/2
zsh 17133 schaefer 10u CHR 136,2 4 /dev/pts/2
zsh 17133 schaefer 11r FIFO 0,7 2256773 pipe
zsh 17133 schaefer 14w FIFO 0,7 2256774 pipe
Note that 14w is connected to 0r and 11r is connected to 1w, all in
the same process. IIRC exactly the same thing happens in at least
some revisions of ksh if you use a built-in construct as a coproc.
The workaround for now is to close the coproc inside the coproc:
% coproc { coproc exit; while read line;do print -r -- "$line:u";done }
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Is it possible to capture stdout and stderr to separate variables in Zsh?
2012-03-07 9:26 ` Nikolai Weibull
2012-03-08 14:53 ` Bart Schaefer
@ 2012-09-10 6:16 ` Han Pingtian
1 sibling, 0 replies; 13+ messages in thread
From: Han Pingtian @ 2012-09-10 6:16 UTC (permalink / raw)
To: zsh-users
On Wed, Mar 07, 2012 at 10:26:57AM +0100, Nikolai Weibull wrote:
> Invoking two additional commands (mktemp and rm) is prohibitively
> expensive on Cygwin for my use case. I used the following solution
> instead:
>
> outs=("${(@0):-"$({ out=$(x) } 2>&1; print $'\0'$out$'\0'$status)"}")
Looks like it can be written as:
outs=("${(0)$({ out=$(x) } 2>&1; print $'\0'$out$'\0'$status)}")
e.g.
% outs=("${(0)$({ out=$(fuser /usr/local/bin/zsh) } 2>&1; print $'\0'$out$'\0'$status)}")
/usr/local/bin/zsh: ee
8013 14594
0
So the $'\n' and $'\0' are both reserved in the nested command
substitution since the whole substitution is in double quote. Not sure
if this is right here.
Thanks.
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2012-09-10 6:26 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-03-06 8:09 Is it possible to capture stdout and stderr to separate variables in Zsh? Nikolai Weibull
2012-03-06 17:16 ` Philippe Troin
2012-03-07 7:01 ` Bart Schaefer
2012-03-07 9:26 ` Nikolai Weibull
2012-03-08 14:53 ` Bart Schaefer
2012-03-30 7:15 ` Nikolai Weibull
2012-03-30 14:49 ` Bart Schaefer
2012-09-10 6:16 ` Han Pingtian
2012-03-07 19:37 ` Philippe Troin
2012-03-08 4:56 ` Bart Schaefer
2012-09-01 11:59 ` Han Pingtian
2012-09-09 19:18 ` Bart Schaefer
2012-08-31 0:40 ` Paul Maisano
Code repositories for project(s) associated with this public inbox
https://git.vuxu.org/mirror/zsh/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).