Moving file descriptors in zsh

file-descriptorszsh

The construction ls 3>&2 2>&1 1>&3- in zsh does not behave in a manner consistent with ksh/bash or with more limited shells like dash that don't support moving file descriptor at all. Instead of emitting the directory contents on standard error or complaining about an invalid file descriptor number it prints nothing. What does moving a file descriptor mean/do in zsh? I've only tested the various shells on OS X so far (using the most recent release installed through homebrew).

First we set up a temporary folder

$ mkdir /tmp/foo
$ cd /tmp/foo
$ touch a
$ touch b

Then we run ls 3>&2 2>&1 1>&3- with bash and ksh, which both support moving file descriptors.

$ bash -c 'ls 3>&2 2>&1 1>&3-'
a       b

$ bash --version | head -n 1
GNU bash, version 4.4.5(1)-release (x86_64-apple-darwin15.6.0)

ksh behaves similarly

$ ksh -c 'ls 3>&2 2>&1 1>&3-'
a       b

$ ksh --version
version         sh (AT&T Research) 93u+ 2012-08-01

dash is an example of a shell that does not support this syntax. It interprets 1>&3- as a badly formatted duplication.

$ dash -c 'ls 3>&2 2>&1 1>&3-'

dash: 1: Syntax error: Bad fd number

zsh, bizarrely, prints nothing.

$ echo -n '<'; zsh -c 'ls 3>&2 2>&1 1>&3-'; echo '>'
<>

$  zsh --version
zsh 5.2 (x86_64-apple-darwin15.4.0)

Is zsh performing the underlying dups and closes in a different order than bash and ksh are? Does it have a bug in its implementation of this feature?

Best Answer

zsh does not support moving file descriptor syntax like bash or ksh. So 1>&3- means redirect both standard output and standard error to file named 3-:

$ echo -n '<'; zsh -c 'ls 3>&2 2>&1 1>&3-'; echo '>'
<>
$ ls
3- a b

For achieving the same moving file descriptor behavior like bash and ksh, in any POSIX shell:

sh -c 'ls 3>&2 2>&1 3>&1 3>&-'

That's what 1>&3- in bash and ksh does internally, duplicated file descriptor 3 to file descriptor 1 then close file descriptor 3.

Related Question