Bash's manual says:
If >&-
or <&-
is preceded by {varname}
, the value of varname defines the file descriptor to close.
So, it's exec {fd}>&-
(or {fd}<&-
) to close it.
$ exec {fd}>foo.out
$ echo "$fd"
10
$ echo hi >&"$fd" # works
$ exec {fd}>&- # close it
$ echo ho >&"$fd" # doesn't work any more
bash: "$fd": Bad file descriptor
$ cat foo.out
hi
exec <&"${ec}"-
moves the fd named in $ec
to stdin (i.e. makes stdin a copy of fd $ec
, then closes fd $ec
). The shell now has its stdin connected to the process substitution, and continues reading input from there. But ruby
probably already read everything, and the pipe would just give an EOF, exiting the shell.
Similarly, exec >&${gr}-
redirects stdout to the fd stored in $gr
(closing $gr
). Any further regular output, like that from ls
goes to the process substitution and the grep
. So, ls
might not produce any visible output, but echo hello
should.
Though as usual, $gr
here should be also quoted to avoid word splitting, since in general, IFS
can contain digits. So that would be better written as exec >&"${gr}"-
.
The fd number you want to modify comes first in the redirections, the default being stdin (0
) for <
and stdout (1
) for >
.