3

I have this file:

1
2
3
4

When I run paste in this manner

paste - - <file

this results

1       2
3       4

so far so good, standard input(redirected from file) is passed twice to paste therefore odd- and even-numbered lines print in pairs.

However, when this is changed to

paste - /dev/fd/0 <file

the output becomes

1       1
2       2
3       3
4       4

paste appears to be opening file twice (leading to two distinct entries in the kernel's file table?), once for the - argument and once again for /dev/fd/0.

I am at a loss to explain this - if I'm interpreting this correctly, both - and /dev/fd/0 ought to be referencing a single kernel file table entry therefore paste should be yielding results identical to the previous case.

5

That's specific to Linux. While on most Unices, opening /dev/fd/n is more or less the same as dup(n) (get a file descriptor to the same open file description as on fd n), on Linux, /dev/fd/n is a symlink to the file open on file descriptor n.

So, on Linux:

paste - /dev/fd/0 < file

is the same as:

paste - file < file

(or paste file file).

The two fds (0 for - and the own obtained by opening /dev/fd/0 or file), are independent and have their own cursor within the file.

You'll also notice that on Linux, you can't use /dev/fd/n with sockets.

Generally on Linux, you only want to use /dev/fd/n with pipes. But in this case

cat file | paste - /dev/fd/0

(or switching to a non-Linux-based OS) won't really help. paste - - works because paste knows it's stdin in both cases. But not here, so it will read a whole chunk (as opposed to a single line) from - (fd 0 to the pipe), and then another chunk from /dev/fd/0 (an independent fd to the same pipe on Linux, but whether those fds point to the same open file description or not doesn't matter for a pipe). Both read()s will read separate parts of the file, but several lines at a time.

You'd need to tell paste to read one byte at a time so it doesn't read more than one line from - before reading a line from /dev/fd/0, which you can probably not do without recompiling. You might be able to get paste to read its stdin one byte at a time with stdbuf, but probably not /dev/fd/0:

$ cat file | paste - /dev/fd/0
1
2
3
4
$ cat file | stdbuf -i1 paste - /dev/fd/0
1       2
        3
        4
  • Indeed - as borne out by the output from { ls -lart /proc/$BASHPID/fd/5 ; } <file 5<&0. I'm baffled as to why linux should choose to implement /dev/fd in this manner – iruvar May 4 '17 at 15:43
  • @iruvar, it has its uses. See here, there, there, there, there – Stéphane Chazelas May 4 '17 at 15:54
  • It seams logical and correct to me. I can not get my head around the alternative. Think what would happen if you made a link to a file hard or soft, and fed them both into paste? It is just another directory entry to the same file, so should act as such. – ctrl-alt-delor May 4 '17 at 16:29
  • @richard, in case your comment was directed at my original comment -now that it has come to light that /dev/fd is implemented using symlinks under linux, I have no issues with paste behaviour under linux whatsoever - however, I was asking why linux did things differently from other Unices in this regard. Stephane's links shed light on how this could be useful under some circumstances, so I'm all good – iruvar May 4 '17 at 17:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.