¿Por qué no puedo leer / dev / stdout con un editor de texto?

9

Recién comencé a aprender cómo Everything Is A File TM en Linux, lo que me hizo preguntarme qué pasaría si literalmente leía de / dev / stdout:

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

(El ^Csoy yo matando el programa después de que se cuelga).

Cuando lo intento vim, aparece el mensaje impensable: "/ dev / stdout" no es un archivo. ¡Jadear!

Entonces, ¿qué ocurre? ¿Por qué recibo mensajes de error o bloqueos cuando intento leer estos "archivos"?

usuario1717828
fuente
1
Lo que vim considera un archivo y lo que se entiende por "todo es un archivo" (sin marca comercial asociada) en * nix no son lo mismo. Ver, por ejemplo, # 1 y # 2 .
Ricitos

Respuestas:

11

¿Por qué me cuelgan?

No está recibiendo "bloqueos" de cat(1)y tail(1), solo están bloqueando la lectura. cat(1)espera la entrada y la imprime tan pronto como ve una línea completa:

$ cat /dev/stdout
foo
foo
bar
bar

Aquí escribí fooEnterbarEnterCTRL- D.

tail(1)espera la entrada y la imprime solo cuando puede detectar EOF:

$ tail /dev/stdout
foo
bar
foo
bar

Aquí escribí de nuevo fooEnterbarEnterCTRL- D.

o mensajes de error

Vim es el único que te da un error. Lo hace porque se ejecuta en stat(2) contra /dev/stdouty descubre que no tiene el S_IFREGbit establecido.

/dev/stdoutes un archivo, pero no un archivo normal . De hecho, hay algo de baile en el núcleo para darle una entrada en el sistema de archivos. En Linux:

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

En OpenBSD:

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

En 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
fuente
5

(Casi) todo es un archivo, pero no todo es un archivo normal . No tiene sentido llamar a un editor de texto en algo que es un archivo especial como un directorio, un socket de red, un puerto serie, etc.

El archivo /dev/stdoutpuede ser una de varias cosas dependiendo de la variante de Unix:

  • un archivo "especial", típicamente un dispositivo de caracteres;
  • un enlace simbólico "mágico" que apunta al archivo que el proceso que accede a él se ha abierto en este descriptor;
  • Un enlace simbólico a uno de los anteriores.

En cualquier caso, abrir /dev/stdoutarchivos similares crea un nuevo descriptor de archivo que está asociado con el mismo archivo que la aplicación ya tiene abierto en el descriptor de archivo 1. “Salida estándar” significa el descriptor de archivo 1, y es solo una convención que se utilice este descriptor de archivo para salida: al núcleo no le importa.

Cuando ejecuta un programa en un terminal, los tres descriptores estándar (0 = entrada estándar, 1 = salida estándar, 2 = error estándar) se abren en el dispositivo terminal. La lectura desde ese dispositivo devuelve caracteres escritos por el usuario, y la escritura en ese dispositivo muestra texto en la ventana del terminal. (No existe una forma estándar, dado un dispositivo terminal, de leer la salida que muestra o inyectarle entradas).

Cuando ejecuta cat /dev/stdout, eso hace exactamente lo mismo que cat /dev/stdino cat /dev/stderr, porque estos tres descriptores de archivo están conectados al mismo archivo: le dice catque lea desde el terminal. Eso es lo que catsin argumento hace también.

Si ejecutó cat /dev/stdout >foo, /dev/stdoutse referiría al archivo foo, ese comando es equivalente a cat foo >foo. Dependiendo de la catimplementación, podría producirse un error (la versión de GNU se queja de que "el archivo de entrada es el archivo de salida"), o podría no hacer nada porque lee del archivo fooque está vacío ( >foosolo lo truncó). Con una versión de catque no detecta este caso especial, si foono está vacío, entonces cat /dev/stdout >>fooo el equivalente cat foo >>fooagregaría el contenido del archivo a sí mismo indefinidamente.

Cuando ejecuta vim /dev/stdout, se queja porque no sabe cómo editar un terminal (eso simplemente no tiene sentido).

Gilles 'SO- deja de ser malvado'
fuente
2

caty tailestá buscando contenido opcional seguido de un final de archivo. /dev/stdoutsigue abierta, por lo que cat, y tailsólo seguir buscando.

Politank-Z
fuente