12

I just started learning how Everything Is A FileTM on Linux, which made me wonder what would happen if I literally read from /dev/stdout:

$ cat /dev/stdout 
^C
$ tail /dev/stdout 
^C

(The ^C is me killing the program after it hangs).

When I try with vim, I get the unthinkable message: "/dev/stdout" is not a file. Gasp!

So what gives, why am I getting hangups or error messages when I try to read these "files"?

user1717828
  • 3,542
  • 1
    What vim considers a file and what is meant by "everything is a file" (no associated trademark) in nix are not the same thing. See e.g. #1* and #2. – goldilocks May 08 '15 at 17:08

4 Answers4

13

why am I getting hangups

You aren't getting "hangups" from cat(1) and tail(1), they're just blocking on read. cat(1) waits for input, and prints it as soon as it sees a complete line:

$ cat /dev/stdout
foo
foo
bar
bar

Here I typed fooEnterbarEnterCTRL-D.

tail(1) waits for input, and prints it only when it can detect EOF:

$ tail /dev/stdout
foo
bar
foo
bar

Here I typed again fooEnterbarEnterCTRL-D.

or error messages

Vim is the only one that gives you an error. It does that because it runs stat(2) against /dev/stdout, and it finds it doesn't have the S_IFREG bit set.

/dev/stdout is a file, but not a regular file. In fact, there's some dance in the kernel to give it an entry in the filesystem. On Linux:

$ ls -l /dev/stdout
lrwxrwxrwx 1 root root 15 May  8 19:42 /dev/stdout -> /proc/self/fd/1

On OpenBSD:

$ ls -l /dev/stdout
crw-rw-rw-  1 root  wheel   22,   1 May  7 09:05:03 2015 /dev/stdout

On FreeBSD:

$ ls -l /dev/stdout
lrwxr-xr-x  1 root  wheel  4 May  8 21:35 /dev/stdout -> fd/1

$ ls -l /dev/fd/1
crw-rw-rw-  1 root  wheel  0x18 May  8 21:35 /dev/fd/1
lcd047
  • 7,238
5

(Almost) everything is a file but not everything is a regular file. It doesn't make sense to call a text editor on something that is a special file such as a directory, a network socket, a serial port, etc.

The file /dev/stdout can be one of several things depending on the unix variant:

  • a “special” file, typically a character device;
  • a “magic” symbolic link that points to the file that the process accessing it has open on this descriptor;
  • a symbolic link to one of the above.

In any case, opening /dev/stdout and similar files creates a new file descriptor that's associated with the same file that the application already has open on file descriptor 1. “Standard output” means file descriptor 1, and it's only a convention that this file descriptor is used for output — the kernel doesn't care.

When you run a program in a terminal, all three standard descriptors (0 = standard input, 1 = standard output, 2 = standard error) are opened on the terminal device. Reading from that device returns characters typed by the user, and writing to that device displays text in the terminal window. (There's no standard way, given a terminal device, to read the output that it displays or to inject input into it.)

When you run cat /dev/stdout, that does exactly the same thing as cat /dev/stdin or cat /dev/stderr, because these three file descriptors are connected to the same file: it tells cat to read from the terminal. That's what cat with no argument does too.

If you ran cat /dev/stdout >foo, then /dev/stdout would refer to the file foo — that command is equivalent to cat foo >foo. Depending on the cat implementation, it might either error out (the GNU version complains that “input file is output file”), or it might do nothing because it reads from the file foo which is empty (>foo just truncated it). With a version of cat that doesn't detect this special case, if foo is not empty, then cat /dev/stdout >>foo or the equivalent cat foo >>foo would append the content of the file to itself indefinitely.

When you run vim /dev/stdout, it complains because it doesn't know how to edit a terminal (that just doesn't make sense).

2

cat and tail are looking for optional content followed by an end of file. /dev/stdout remains open, so cat and tail just keep looking.

-5

please try these

sudo su
chmod +x /dev/stdout
chmod +x /dev/stderr
exit su

I tried and worked and you will learn by trying :)

I don't know why it's necessary? explain it anybody?

stdout permissions info stdin permissions info MY GOAL  HAPPY OF THE END