How can I pipe only stderr in zsh?

326

With zsh and with the mult_ios option on (on by default), in:

echo hi 2>&1 1>/dev/null | cat

The 1> /dev/null | cat is seen as a multiple redirection of echo's stdout.

So echo's stdout is now redirected to both /dev/null and a pipe to cat (as if using tee).

To cancel that multiple redirection, you can do:

echo hi 2>&1 >&- > /dev/null | cat

That is, closing stdout (cancelling the piping) before redirecting to /dev/null

Or use a command group or subshell like:

{echo hi 2>&1 1>/dev/null} | cat 
(echo hi 2>&1 1>/dev/null) | cat

That way, echo's stdout is only redirected explicitly once (the pipe redirection is applied to the group/subshell and inherited by echo).

Or you can disable multios altogether:

(setopt nomultios; echo hi 2>&1 > /dev/null | cat)

Alternatively, you could use process substitution instead of a pipe:

echo hi 2> >(cat) > /dev/null

Beware however that when job control is off (like in scripts), the cat process will be running asynchronously (as if started with &).

Share:
326

Related videos on Youtube

Nadeem Ahmad
Author by

Nadeem Ahmad

Updated on September 18, 2022

Comments

  • Nadeem Ahmad
    Nadeem Ahmad over 1 year

    Actually I am facing issue in the TouchID implementation. I want to implement a passcode functionality like Apple. My is problem is that I don't want to show any alert to the user like Apple.

    NSString *myLocalizedReasonString = <#String explaining why app needs authentication#>;
    if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
    [myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
    localizedReason:myLocalizedReasonString
    reply:^(BOOL success, NSError *error) {
    

    Here if I don't send myLocalizedReasonString the app will crash.

  • Tavian Barnes
    Tavian Barnes about 8 years
    Thanks! Another way to get around it is (echo hi 2>&1 1>/dev/null) | cat.
  • Stéphane Chazelas
    Stéphane Chazelas about 8 years
    @TavianBarnes, good point, thanks. I've added it to the answer for completeness. It also works with a command group ({echo...}|cat)