What's the correct way to redirect both stdout

2020-07-06 04:37发布

问题:

Here's the concrete task I'm trying to accomplish. zsh behaves the way I like

$ zsh
$ which clang > /dev/null 2&>1 && echo clang || echo gcc
clang
$ which doesntexist > /dev/null 2&>1 && echo doesntexist || echo gcc
gcc

But, in bash:

$ bash
$ which clang > /dev/null 2&>1 && echo clang || echo gcc
gcc

Here's the general case:

$ which clang > /dev/null 2&>1; echo $?
1
$ which clang; echo $?
/usr/bin/clang
0

There's something wrong with how I'm redirecting output. What's the right way?

回答1:

I think you're redirecting the wrong way:

which clang > /dev/null 2&>1; echo $?

Should be

which clang > /dev/null 2>&1; echo $?

It's probably how either shells allow the former method. In bash it's not the right way. Bash would interpret it instead like:

which clang >/dev/null 2 &>1; echo $?

In which 2 is added as an argument.

You can verify that by creating a function like

e() { echo "$@" >e.log; }

And call it as:

e 1 >/dev/null 2&>/dev/null

And you would get 1 2 in e.log.

In bash it's also simpler if you call your command like this:

which clang &>/dev/null; echo $?

Also rather than calling an external binary like which, use type -P instead. No need to redirect stderr output too.

type -P clang >/dev/null; echo $?


回答2:

You're using zsh's &> operator, which redirects stderr and stdout. The way you've used it suggests you meant ... > /dev/null 2>&1 instead.

I would do this as:

$ cc=$( type -P clang gcc othercc | head -n 1 )
$ echo $cc
/usr/bin/clang


回答3:

Use this:

which gcc >& /dev/null && echo gcc || echo clang

Also you can use this:

[[ $(which gcc) ]] && echo gcc || echo clang # prints gcc
[[ $(which clang) ]] && echo gcc || echo clang # prints clang

This works because in [[ ]] empty strings are falsey.