linux - archivos - confundido acerca de stdin, stdout y stderr?
stdout php (9)
stdin
Lee la entrada a través de la consola (por ejemplo, la entrada del teclado). Usado en C con scanf
scanf(<formatstring>,<pointer to storage> ...);
stdout
Produce salida a la consola. Utilizado en C con printf
printf(<string>, <values to print> ...);
stderr
Produce salida de ''error'' a la consola. Usado en C con fprintf
fprintf(stderr, <string>, <values to print> ...);
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 programa ( ps | grep <userid>
).
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>
.
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 programa 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.
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 programas 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 programas que se ejecutan simultáneamente. para identificarse a sí mismos ".
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
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
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 programa , no desde la perspectiva del kernel.
Cuando un programa necesita imprimir la salida, normalmente se imprime en "salida estándar". Un programa normalmente imprime la salida a salida estándar con printf
, que imprime SÓLO a la salida estándar.
Cuando un programa necesita imprimir información de error (no necesariamente excepciones, son construcciones de lenguaje de programació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 programas 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 programa conectadas a la entrada estándar del siguiente programa 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. :)
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 programas 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 programación. Esto es solo una convención, y no es aplicado por el sistema operativo.
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 programa, 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 corrientes 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
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
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 <inputfile 2>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 degrep
.
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.