12

Let's assume that infile contains a specific text, and I were to execute the following set of commands:

exec 3<infile

cat -n <&3

cat -n <&3

The first instance of cat will display the file's contents, but the second time does not seem to be doing anything. Why do they differ?

2 Answers2

29

They look like the same command but the reason they differ is the system state has changed as a result of the first command. Specifically, the first cat consumed the entire file, so the second cat has nothing left to read, hits EOF (end of file) immediately, and exits.

The reason behind this is you are using the exact same file description (the one you created with exec < infile and assigned to the file descriptor 3) for both invocations of cat. One of the things associated with an open file description is a file offset. So, the first cat reads the entire file, leaves the offset at the end, and the second one tries to pick up from the end of the file and finds nothing to read.

jw013
  • 51,212
12

Just to add to @jw013's fine answer, it may help to realise that it's the same as

{
   cat -n
   cat -n
} < infile

< file being short for 0< file, that is use file descriptor 0 instead of 3.

And just to confuse the matter a little, this version:

exec 3< infile
cat -n /dev/fd/3
cat -n /dev/fd/3

Behaves differently depending on the OS you run it in and the type of infile (regular file vs pipe vs device...)

On Solaris and most commercial Unices, an open("/dev/fd/3") is more or less equivalent to a dup(3) (so < /dev/fd/3 is about the same as <&3), while on Linux, for regular files, /dev/fd/3 is implemented as a symlink to the original file, so open("/dev/fd/3") opens it anew from the start (and possibly with different flags from the fd 3).