Linux – Why BASH Process Substitution Fails with Some Commands

bashcommand linelinuxprocess-substitutionshell

On occasion process substitution will not work as expected. Here is an example:

Input:

gcc <(echo 'int main(){return 0;}')

Output:

/dev/fd/63: file not recognized: Illegal seek
collect2: error: ld returned 1 exit status

Input:

But it works as expected when used with a different command:

grep main <(echo 'int main(){return 0;}')

Output:

int main(){return 0;}

I have noticed similar failures with other commands (i.e. the command expecting the file from the process substitution can't use /dev/fd/63 or similar). This failure with gcc is just the most recent. Is there some general rule that I should be aware of to determine when process substitution will fail in this way and should not be used?

I am using this BASH version on Ubuntu 12.04 (I've also seen this in arch and debian):
GNU bash, version 4.3.11(1)-release (i686-pc-linux-gnu)

Best Answer

Process substitution results in a special file (like /dev/fd/63 in your example) that behaves like the read end of a named pipe. This file can be opened and read, but not written, not seeked.

Commands that treat their arguments as pure streams work while commands that expect to seek in files they are given (or write to them) won't work. The kind of command that will work is what is usually considered a filter: cat, grep, sed, gzip, awk, etc... An example of a command that won't work is an editor like vi or a file operation like mv.

gcc wants to be able to perform random access on its input files to detect what language they are written in. If you instead give gcc a hint about the input file's language, it's happy to stream the file:

gcc -x c <(echo 'int main(){return 0;}')

The simpler more straightforward form without process substitution also works:

echo 'int main(){return 0;}' | gcc -x c -

Note that this is not specific to bash. All shells that support process substitution behave the same way.

Related Question