Redirections to specific file descriptors use
3< file. Process substitution uses
<( ... ). To combine the two you need to use both:
3< <( ... )
The space is important — otherwise it's interpreted as an attempted here document that is terminated with
(, but that isn't valid and you'll get a parse error.
gpg command line needs to be:
gpg --enable-special-filenames --verify --batch -- '-&3' '-&4' \
3< <(curl -s https://www.gnupg.org/ftp/gcrypt/gnupg/gnupg-2.0.29.tar.bz2.sig) \
4< <(curl https://www.gnupg.org/ftp/gcrypt/gnupg/gnupg-2.0.29.tar.bz2)
This redirects the output of the first
curl command into descriptor 3, and the second into descriptor 4, in just the same way as if you read into them from a normal file.
The way that
<( ... ) works is that it runs the command with its output connected to either a FIFO or an entry under
/dev/fd, and then
<( ... ) gets replaced in the command line with the path to that file as an ordinary argument, just as though it'd been written there in the first place. The file path can then be used with other constructs, like redirection.
Your original command ends up running
gpg ... 3/dev/fd/63 4/dev/fd/64, and then
curl finds that nobody is interested in what it's writing and reports that error. I also got an error from
gpg itself saying that those files don't exist, although it was buried in the