the following command works in dash but fails in bash with "Bad file descriptor".

$ dash -c 'out=$(echo "to fd3" >&3; echo "to stdout") 3>&1; echo "out: $out"'
to fd3
out: to stdout

$ bash -c 'out=$(echo "to fd3" >&3; echo "to stdout") 3>&1; echo "out: $out"'
bash: 3: Bad file descriptor
out: to stdout

when i replace the command substition with a subshell then it seems to work in dash and bash.

$ dash -c '(echo "to fd3" >&3; echo "to stdout") 3>&1'
to fd3
to stdout

$ bash -c '(echo "to fd3" >&3; echo "to stdout") 3>&1'
to fd3
to stdout


$ bash --version
GNU bash, version 4.4.12(1)-release (x86_64-unknown-linux-gnu)

don't know how to get dash version. the man page on my system is dated January 19, 2003.


i looked up how bash and dash executes a command. this is what i found.

for bash: https://www.gnu.org/software/bash/manual/bashref.html#Shell-Operation

for dash: http://man7.org/linux/man-pages/man1/dash.1.html (section "Simple Commands")

as far as i understand both do expansions before redirections. command substitution is an expansion. so it makes sense that file descriptor 3 is not set up in the command substitution.

why does it work in dash? why does it not work in bash? is it a bug in dash? or bash? is it a valid construct at all?


Whether redirections are performed before or after assignment expansion is unspecified by POSIX when there's no command, so both are valid and you can't rely on either. So portably, you'd need:

{ out=$(echo "to fd3" >&3; echo "to stdout"); } 3>&1

AT&T ksh and the Bourne shell behave like bash; zsh, pdksh, yash behave like dash in this instance.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.