¿Confundido sobre stdin, stdout y stderr?

Estoy bastante confundido con el propósito de estos tres archivos. Si mi comprensión es correcta, stdin es el archivo en el que un progtwig escribe en sus solicitudes para ejecutar una tarea en el proceso, stdout es el archivo en el que el kernel escribe su salida y el proceso que lo solicita accede a la información, y stderr es el archivo en el que se ingresan todas las excepciones. Al abrir estos archivos para comprobar si realmente ocurren, ¡descubrí que nada parece sugerirlo!

Lo que me gustaría saber es cuál es exactamente el propósito de estos archivos, ¡una respuesta absolutamente estúpida con muy poca jerga tecnológica!

Entrada estándar : este es el manejador de archivo que lee su proceso para obtener información de usted.

Salida estándar : su proceso escribe información normal en este manejador de archivo.

Error estándar : el proceso escribe información de error en este manejador de archivo.

Eso es tan estúpido como puedo hacerlo 🙂

Por supuesto, eso es principalmente por convención. No hay nada que le impida escribir la información de error en la salida estándar si lo desea. Incluso puede cerrar los tres manejadores de archivos totalmente y abrir sus propios archivos para E / S.

Cuando se inicia el proceso, ya debe tener estos controles abiertos y solo puede leer y escribir en ellos.

Por defecto, probablemente estén conectados a su dispositivo terminal (por ejemplo, /dev/tty ) pero las shells le permitirán establecer conexiones entre estos identificadores y archivos y / o dispositivos específicos (o incluso canalizaciones a otros procesos) antes de su proceso comienza (algunas de las manipulaciones posibles son bastante ingeniosas).

Un ejemplo:

 my_prog errorfile | grep XYZ 

que lo hará:

  • crea un proceso para my_prog .
  • abra el archivo de entrada como su entrada estándar (identificador de archivo 0).
  • abra errorfile como su error estándar (identificador de archivo 2).
  • crea otro proceso para grep .
  • conecte la salida estándar de my_prog a la entrada estándar de grep .

Re su comentario:

Cuando abro estos archivos en la carpeta / dev, ¿cómo es que nunca consigo ver el resultado de un proceso en ejecución?

Es porque no son archivos normales. Si bien UNIX presenta todo como un archivo en un sistema de archivos en alguna parte, eso no lo hace en los niveles más bajos. La mayoría de los archivos en la jerarquía /dev son dispositivos de caracteres o bloques, efectivamente un controlador de dispositivo. No tienen un tamaño pero tienen un número de dispositivo mayor y menor.

Cuando los abre, está conectado al controlador del dispositivo en lugar de a un archivo físico, y el controlador del dispositivo es lo suficientemente inteligente como para saber que los procesos separados deben manejarse por separado.

Lo mismo es cierto para el sistema de archivos Linux /proc . Esos no son archivos reales, solo entradas estrechamente controladas a la información del kernel.

Sería más correcto decir que stdin , stdout y stderr son “flujos de E / S” en lugar de archivos. Como habrás notado, estas entidades no viven en el sistema de archivos. Pero la filosofía de Unix, en lo que respecta a I / O, es “todo es un archivo”. En la práctica, eso realmente significa que puede usar las mismas funciones e interfaces de la biblioteca ( printf , scanf , read , write , select , etc.) sin preocuparse de si la secuencia de E / S está conectada a un teclado, un archivo de disco, una socket, una tubería o alguna otra abstracción de E / S.

La mayoría de los progtwigs necesitan leer los errores de entrada, escritura y registro, por lo que stdin , stdout y stderr están predefinidos para usted, como una conveniencia de progtwigción. Esto es solo una convención, y no es aplicado por el sistema operativo.

Me temo que tu comprensión es completamente al revés. 🙂

Piense en “estándar en”, “estándar fuera” y “error estándar” desde la perspectiva del progtwig , no desde la perspectiva del kernel.

Cuando un progtwig necesita imprimir la salida, normalmente se imprime en “salida estándar”. Un progtwig normalmente imprime la salida a salida estándar con printf , que imprime SÓLO a la salida estándar.

Cuando un progtwig necesita imprimir información de error (no necesariamente excepciones, son construcciones de lenguaje de progtwigción, impuestas a un nivel mucho más alto), normalmente se imprime como “error estándar”. Normalmente lo hace con fprintf , que acepta una secuencia de archivos para usar al imprimir. La secuencia de archivos podría ser cualquier archivo abierto para escritura: salida estándar, error estándar o cualquier otro archivo que se haya abierto con fopen o fdopen .

“estándar en” se usa cuando el archivo necesita leer entrada, usando fread o fgets , o getchar .

Cualquiera de estos archivos puede redirigirse fácilmente desde el shell, así:

 cat /etc/passwd > /tmp/out # redirect cat's standard out to /tmp/foo cat /nonexistant 2> /tmp/err # redirect cat's standard error to /tmp/error cat < /etc/passwd # redirect cat's standard input to /etc/passwd 

O bien, toda la enchilada:

 cat < /etc/passwd > /tmp/out 2> /tmp/err 

Hay dos advertencias importantes: Primero, "estándar en", "estándar fuera" y "error estándar" son solo una convención. Son una convención muy fuerte , pero todo es solo un acuerdo de que es muy bueno poder ejecutar progtwigs como este: grep echo /etc/services | awk '{print $2;}' | sort grep echo /etc/services | awk '{print $2;}' | sort grep echo /etc/services | awk '{print $2;}' | sort y tener las salidas estándar de cada progtwig conectadas a la entrada estándar del siguiente progtwig en la tubería.

En segundo lugar, he dado las funciones estándar de ISO C para trabajar con flujos de archivos (objetos FILE * ) - a nivel del kernel, son todos los descriptores de archivos (referencias int a la tabla de archivos) y operaciones de bajo nivel como read y write , que no hacen el almacenamiento en búfer feliz de las funciones ISO C. Pensé en mantenerlo simple y usar las funciones más fáciles, pero pensé que de todos modos debería conocer las alternativas. 🙂

Como complemento de las respuestas anteriores, aquí hay un resumen sobre las redirecciones: Redirections cheatsheet

stdin

Lee la entrada a través de la consola (por ejemplo, la entrada del teclado). Usado en C con scanf

 scanf(, ...); 

stdout

Produce salida a la consola. Utilizado en C con printf

 printf(,  ...); 

stderr

Produce salida de ‘error’ a la consola. Usado en C con fprintf

 fprintf(stderr, ,  ...); 

Redirección

La fuente de stdin se puede redirigir. Por ejemplo, en lugar de venir de la entrada del teclado, puede provenir de un archivo ( echo < file.txt ) u otro progtwig ( ps | grep ).

Los destinos para stdout, stderr también se pueden redireccionar. Por ejemplo, stdout se puede redireccionar a un archivo: ls . > ls-output.txt ls . > ls-output.txt , en este caso el resultado se escribe en el archivo ls-output.txt . Stderr se puede redirigir con 2> .

El uso de ps -aux revela los procesos actuales, que se enumeran en / proc / as / proc / (pid) /, al llamar a cat / proc / (pid) / fd / 0 imprime todo lo que se encuentra en la salida estándar de ese proceso, creo. Así que tal vez,

/ proc / (pid) / fd / 0 – Archivo de salida estándar
/ proc / (pid) / fd / 1 – Archivo de entrada estándar
/ proc / (pid) / fd / 2 – Archivo de error estándar

por ejemplo mi ventana de terminal

Pero solo funcionó muy bien para / bin / bash, otros procesos generalmente no tenían nada en 0 pero muchos tenían errores escritos en 2

Creo que la gente que dice que stderr debería usarse solo para mensajes de error es engañosa. También se debe usar para mensajes informativos que están destinados al usuario que ejecuta el comando y no a los posibles consumidores intermedios de los datos (es decir, si ejecuta un shell pipe encadenando varios comandos, no quiere mensajes informativos como “obtener el elemento 30 de 42424 “para aparecer en estándar, ya que confundirán al consumidor, pero es posible que aún desee que el usuario los vea.

Consulte http://www.jstorimer.com/blogs/workingwithcode/7766119-when-to-use-stderr-instead-of-stdout para obtener una justificación histórica:

“Todos los progtwigs colocaron diagnósticos en la salida estándar. Esto siempre había causado problemas cuando la salida se redirigía a un archivo, pero se volvió intolerable cuando la salida se enviaba a un proceso desprevenido. Sin embargo, no quería violar la simplicidad de la entrada estándar. modelo de salida estándar, la gente toleró este estado de cosas a través de v6. Poco después Dennis Ritchie cortó el nudo gordiano al introducir el archivo de error estándar. Eso no fue suficiente. Con los diagnósticos de tuberías podría provenir de cualquiera de varios progtwigs que se ejecutan simultáneamente. para identificarse a sí mismos “.

stderr no hará el almacenamiento en memoria caché de IO así que si nuestra aplicación necesita imprimir información crítica del mensaje (algunos errores, excepciones) a la consola o al archivo, utilícelo donde use stdout para imprimir información de registro general, ya que usa el almacenamiento en memoria caché de IO. antes de escribir nuestros mensajes a la aplicación de archivo puede cerrarse, dejando la depuración compleja

Para obtener información autorizada sobre estos archivos, consulte las páginas man, ejecute el comando en su terminal.

 $ man stdout 

Pero para una respuesta simple, cada archivo es para:

stdout para un flujo de salida

stdin para una entrada de flujo

stderr para imprimir errores o mensajes de registro.

Cada progtwig Unix tiene cada una de esas transmisiones.

Un archivo con almacenamiento en búfer asociado se denomina secuencia y se declara como un puntero a un tipo definido ARCHIVO. La función fopen () crea ciertos datos descriptivos para una secuencia y devuelve un puntero para designar la secuencia en todas las transacciones posteriores. Normalmente hay tres flujos abiertos con punteros constantes declarados en el encabezado y asociados con los archivos abiertos estándar. Al inicio del progtwig, tres flujos están predefinidos y no necesitan abrirse explícitamente: entrada estándar (para leer la entrada convencional), salida estándar (para escribir salida convencional) y error estándar (para escribir la salida de diagnóstico). Cuando se abre, la secuencia de error estándar no está totalmente almacenada en el búfer; la entrada estándar y las streams de salida estándar están completamente almacenadas en el búfer si y solo si se puede determinar que la transmisión no hace referencia a un dispositivo interactivo

https://www.mkssoftware.com/docs/man5/stdio.5.asp