5

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

versions:

$ 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.


research:

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?

1 Answer 1

9

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.

4
  • Why using { } makes it more portable? Does it impose a precedence rule between redirection and assignment expansion (and if so which one) or is there something else to it? { } won't spawn a subshell, right?
    – The Quark
    Nov 5, 2021 at 10:10
  • 1
    @TheQuark, it did spawn a subshell in the Bourne shell. Not in POSIX / modern shells. Here you're redirecting the command group, so there's not question that redirections within commands inside the command group could be done before. Nov 5, 2021 at 10:51
  • Ah, the explanation is lower here: The shell has several programming constructs that are "compound commands", [...]. Each of these compound commands has a reserved word or control operator at the beginning, and a corresponding terminator reserved word or operator at the end. In addition, each can be followed by redirections on the same line as the terminator. Each redirection shall apply to all the commands within the compound command that do not explicitly override that redirection.
    – The Quark
    Nov 5, 2021 at 13:09
  • (Just as reference) The key sentence in the unspecified by POSIX when there's no command link is: In the preceding list, the order of steps 3 and 4 may be reversed if no command name results from step 2 or if the command name matches the name of a special built-in utility; see Special Built-In Utilities.
    – The Quark
    Nov 7, 2021 at 12:14

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .