bash command substitution with redirection: bad file descriptor
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.
Related videos on Youtube
Lesmana
Updated on September 18, 2022Comments
-
Lesmana almost 2 years
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?
-
The Quark over 2 yearsWhy 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? -
Stéphane Chazelas over 2 years@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.
-
The Quark over 2 yearsAh, 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 over 2 years(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.