I'm trying to pass information into a program that doesn't accept input from stdin. To do this, I'm using the /dev/stdin as an argument and then trying to pipe in my input. I've noticed that if I do this with a pipe character:
[pkerp@comp ernwin]$ cat fess/structures/168d.pdb | MC-Annotate /dev/stdin
I get no output. If, however, I do the same thing using the left caret character, it works fine:
[pkerp@plastilin ernwin]$ MC-Annotate /dev/stdin < fess/structures/168d.pdb
Residue conformations -------------------------------------------
A1 : G C3p_endo anti
A2 : C C3p_endo anti
A3 : G C3p_endo anti
My question is, what is difference between these two operations and why do they give a different outcome? As a bonus question, is there a proper term for specifying input using the '<' symbol?
Update:
My current best guess is that something internal to the program being run makes use of seeking within the file. The answers below seem to suggest that it has something to do with the file pointers but running the following little test program:
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *f = fopen(argv[1], "r");
char line[128];
printf("argv[1]: %s f: %d\n", argv[1], fileno(f));
while (fgets(line, sizeof(line), f)) {
printf("line: %s\n", line);
}
printf("rewinding\n");
fseek(f, 0, SEEK_SET);
while (fgets(line, sizeof(line), f)) {
printf("line: %s\n", line);
}
fclose(f);
}
indicates that everything occurs identically up until the fseek
function call:
[pete@kat tmp]$ cat temp | ./a.out /dev/stdin
argv[1]: /dev/stdin f: 3
line: abcd
rewinding
===================
[pete@kat tmp]$ ./a.out /dev/stdin < temp
argv[1]: /dev/stdin f: 3
line: abcd
rewinding
line: abcd
Using process substitution as Christopher Neylan suggested leads to the program above hanging without even reading the input, which also seems a little strange.
[pete@kat tmp]$ ./a.out /dev/stdin <( cat temp )
argv[1]: /dev/stdin f: 3
Looking at the strace output confirms my suspicion that a seek operation is attempted which fails in the pipe version:
_llseek(3, 0, 0xffffffffffd7c7c0, SEEK_CUR) = -1 ESPIPE (Illegal seek)
And succeeds in the redirect version.
_llseek(3, 0, [0], SEEK_CUR) = 0
The moral of story: don't haphazardly try to replace an argument with /dev/stdin
and try to pipe to it. It might work, but it just as well might not.