You were really close:
tr "o" "a" < <(echo "Foo")
The substitution <()
makes a file descriptor and just pastes the path to the shell. For comprehension just execute:
<(echo blubb)
You will see the error:
-bash: /dev/fd/63: Permission denied
That's why it just pastes /dev/fd/63
into the shell and /dev/fd/63
is not excutable, because it's a simple pipe. In the tr
-example above, it's echo "Foo"
that writes to the pipe and via input redirection <
it's the tr
command that reads from the file descriptor.
Process substitution is a feature that originated in the Korn shell in the 80s (in ksh86). At the time, it was only available on systems that had support for /dev/fd/<n>
files.
Later, the feature was added to zsh
(from the start: 1990) and bash
(in 1993). zsh
was using temporary named pipes to implement it, while bash
was using /dev/fd/<n>
where available and named pipes otherwise. zsh
switched to using /dev/fd/<n>
where available in 2.6-beta17
in 1996.
Support for process substitution via named pipes on systems without /dev/fd
was only added to ksh
in ksh93u+
in 2012. The public domain clone of ksh
doesn't support it.
To my knowledge, no other Bourne-like shell supports it (rc
, es
, fish
, non-Bourne-like shells support it but with a different syntax). yash
has a <(...)
construct, but that's for process redirection.
While quite useful, the feature was never standardized by POSIX. So, one can't expect to find it in sh
, so shouldn't use it in a sh
script.
Though the behaviour for <(...)
is unspecified in POSIX, (so there would be no harm in retaining it), bash
disables the feature when called as sh
or when called with POSIXLY_CORRECT=1
in its environment.
So, if you have a script that uses <(...)
, you should use a shell that supports the feature to interpret it like zsh
, bash
or AT&T ksh
(of course, you need to make sure the rest of the syntax of script is also compatible with that shell).
In any case:
cat <(cmd)
Can be written:
cmd | cat
Or just
cmd
For a command other than cat
(that needs to be passed data via a file given as argument), on systems with /dev/fd/x
, you can always do:
something | that-cmd /dev/stdin
Or if you need that-cmd
's stdin to be preserved:
{ something 3<&- | that-cmd /dev/fd/4 4<&0 <&3 3<&-; } 3<&0
Best Answer
Process substitution was already there in ksh86 and the release notes mention as a difference from the 02/21/85 version is that it was now documented, so presumably it was already there earlier. When it was designed/introduced exactly, we may have to ask David Korn, but it probably doesn't matter, since it probably never got very far out of Bell labs anyway before ksh88.
99% of bash features come either from the Bourne shell, the Korn shell, csh, tcsh or zsh. It's always difficult to find out when and where things were introduced especially when considering that many features of ksh were never documented or documented long after they were introduced.