En programación informática , los flujos estándar son canales de comunicación de entrada y salida preconectados [1] entre un programa informático y su entorno cuando comienza su ejecución. Las tres conexiones de entrada/salida (E/S) se denominan entrada estándar ( stdin ), salida estándar ( stdout ) y error estándar ( stderr ). Originalmente, la E/S se realizaba a través de una consola del sistema conectada físicamente (entrada a través del teclado, salida a través del monitor), pero los flujos estándar abstraen esto. Cuando se ejecuta un comando a través de un shell interactivo , los flujos suelen estar conectados a la terminal de texto en la que se ejecuta el shell, pero se pueden cambiar con una redirección o una canalización . De forma más general, un proceso hijo hereda los flujos estándar de su proceso padre .
Los usuarios generalmente conocen los flujos estándar como canales de entrada y salida que manejan datos provenientes de un dispositivo de entrada o que escriben datos desde la aplicación. Los datos pueden ser texto con cualquier codificación o datos binarios . Cuando un programa se ejecuta como un demonio , su flujo de error estándar se redirige a un archivo de registro, generalmente con fines de análisis de errores.
Los flujos se pueden utilizar para encadenar aplicaciones, lo que significa que el flujo de salida de un programa se puede redirigir para que sea el flujo de entrada de otra aplicación. En muchos sistemas operativos, esto se expresa enumerando los nombres de las aplicaciones, separados por el carácter de barra vertical, por este motivo, a menudo llamado carácter de canalización . Un ejemplo bien conocido es el uso de una aplicación de paginación , como more , que proporciona al usuario control sobre la visualización del flujo de salida en la pantalla.
En la mayoría de los sistemas operativos anteriores a Unix , los programas tenían que conectarse explícitamente a los dispositivos de entrada y salida apropiados. Las complejidades específicas del sistema operativo hicieron que esta fuera una tarea de programación tediosa. En muchos sistemas era necesario obtener el control de las configuraciones del entorno, acceder a una tabla de archivos local, determinar el conjunto de datos deseado y manejar el hardware correctamente en el caso de un lector de tarjetas perforadas , una unidad de cinta magnética , una unidad de disco , una impresora de línea , una perforadora de tarjetas o una terminal interactiva.
Uno de los avances revolucionarios de Unix fueron los dispositivos abstractos , que eliminaron la necesidad de que un programa supiera o se preocupara por el tipo de dispositivos con los que se estaba comunicando [ cita requerida ] . Los sistemas operativos más antiguos obligaban al programador a utilizar una estructura de registros y, con frecuencia, una semántica de datos no ortogonal y un control de dispositivos. Unix eliminó esta complejidad con el concepto de flujo de datos: una secuencia ordenada de bytes de datos que se pueden leer hasta el final del archivo . Un programa también puede escribir bytes según lo desee y no necesita, ni puede, declarar fácilmente su recuento o agrupación.
Otro gran avance de Unix fue asociar automáticamente la entrada y la salida al teclado y la pantalla del terminal, respectivamente, de forma predeterminada [ cita requerida ] : el programa (y el programador) no hacían absolutamente nada para establecer la entrada y la salida para un programa de entrada-proceso-salida típico (a menos que eligiera un paradigma diferente). En contraste, los sistemas operativos anteriores generalmente requerían algún lenguaje de control de tareas (a menudo complejo ) para establecer conexiones, o la carga equivalente tenía que ser orquestada por el programa. [ cita requerida ]
Dado que Unix proporcionaba flujos estándar, el entorno de ejecución C de Unix también estaba obligado a soportarlos. Como resultado, la mayoría de los entornos de ejecución C (y sus descendientes ), independientemente del sistema operativo, brindan una funcionalidad equivalente.
La entrada estándar es un flujo de datos desde el cual un programa lee sus datos de entrada. El programa solicita transferencias de datos mediante el uso de la operación de lectura . No todos los programas requieren una entrada de flujo de datos. Por ejemplo, los programas dir y ls (que muestran los nombres de los archivos contenidos en un directorio) pueden tomar argumentos de línea de comandos , pero realizan sus operaciones sin ninguna entrada de datos de flujo de datos.
A menos que se redirija , la entrada estándar se hereda del proceso padre. En el caso de un shell interactivo, esto suele estar asociado con el dispositivo de entrada de un terminal (o pseudoterminal ) que, en última instancia, está vinculado al teclado del usuario .
En los sistemas POSIX , el descriptor de archivo para la entrada estándar es 0 (cero); la definición POSIX es ; la abstracción C correspondiente se proporciona a través de la variable global. De manera similar, la variable C++ global de tipo proporciona una abstracción a través de C++ streams . Existen abstracciones similares en las bibliotecas de E/S estándar de prácticamente todos los lenguajes de programación .<unistd.h>
STDIN_FILENO
<stdio.h>
FILE* stdin
std::cin
<iostream>
La salida estándar es un flujo en el que un programa escribe sus datos de salida. El programa solicita la transferencia de datos con la operación de escritura . No todos los programas generan una salida. Por ejemplo, el comando de cambio de nombre de archivo (también llamado mv , move o ren ) no indica si se realizó correctamente.
A menos que se redirija , la salida estándar se hereda del proceso principal. En el caso de un shell interactivo, normalmente es la terminal de texto que inició el programa.
El descriptor de archivo para la salida estándar es 1 (uno); la definición POSIX <unistd.h>
es STDOUT_FILENO
; la <stdio.h>
variable C correspondiente es FILE* stdout
; de manera similar, la <iostream>
variable C++ es std::cout
.
El error estándar es otro flujo de salida que suelen utilizar los programas para generar mensajes de error o diagnósticos. Es un flujo independiente de la salida estándar y se puede redirigir por separado.
Esto resuelve el problema del semipredicado , permitiendo distinguir la salida de los errores, y es análogo a una función que devuelve un par de valores – ver Problema del semipredicado: retorno de múltiples valores . El destino habitual es la terminal de texto que inició el programa para proporcionar la mejor posibilidad de ser visto incluso si se redirige la salida estándar (por lo que no se observa fácilmente). Por ejemplo, la salida de un programa en una tubería se redirige a la entrada del siguiente programa o un archivo de texto, pero los errores de cada programa siguen yendo directamente a la terminal de texto para que el usuario pueda revisarlos en tiempo real. [2]
Es aceptable y normal dirigir la salida estándar y el error estándar al mismo destino, como la terminal de texto. Los mensajes aparecen en el mismo orden en que el programa los escribe, a menos que se utilice un buffer . Por ejemplo, en situaciones comunes, el flujo de error estándar no se almacena en buffer, pero el flujo de salida estándar sí se almacena en buffer de línea; en este caso, el texto escrito posteriormente en el error estándar puede aparecer antes en la terminal, si el buffer del flujo de salida estándar aún no está lleno.
El descriptor de archivo para el error estándar está definido por POSIX como 2 (dos); el archivo de encabezado <unistd.h>STDERR_FILENO
proporciona el símbolo ; [3] la <stdio.h>
variable C correspondiente es FILE* stderr
. El <iostream>
encabezado estándar de C++ proporciona dos variables asociadas con este flujo: std::cerr
y std::clog
, la primera no tiene búfer y la segunda utiliza el mismo mecanismo de búfer que todos los demás flujos de C++.
Los shells de estilo Bourne permiten redirigir el error estándar al mismo destino al que se dirige la salida estándar mediante
2>&1
Los shells de estilo csh permiten redirigir el error estándar al mismo destino al que se dirige la salida estándar mediante
>&
El error estándar se agregó a Unix en la década de 1970 después de varias ejecuciones de fotocomposición inútiles que terminaron con mensajes de error compuestos en lugar de mostrarse en la terminal del usuario. [4]
Fortran tiene el equivalente de los descriptores de archivos de Unix: por convención, muchas implementaciones de Fortran utilizan números de unidad UNIT=5
para stdin, UNIT=6
stdout y UNIT=0
stderr. En Fortran-2003, el ISO_FORTRAN_ENV
módulo intrínseco se estandarizó para incluir las constantes nombradas INPUT_UNIT
, OUTPUT_UNIT
y ERROR_UNIT
para especificar de manera portable los números de unidad.
! FORTRAN 77 ejemplo PROGRAMA NÚMERO ENTERO PRINCIPAL LEER ( UNIDAD = 5 , * ) NÚMERO ESCRIBIR ( UNIDAD = 6 , '(A,I3)' ) ' EL NÚMERO ES: ' , NÚMERO FIN
! Programa de ejemplo de Fortran 2003 uso principal iso_fortran_env implícito ninguno entero :: número lectura ( unidad = UNIDAD_DE_ENTRADA , * ) número escritura ( unidad = UNIDAD_DE_SALIDA , '(a,i3)' ) 'El número es: ' , número fin del programa
ALGOL 60 fue criticado por no tener acceso estándar a archivos. [ cita requerida ]
Las facilidades de entrada y salida de ALGOL 68 se denominaron colectivamente transput. [5] Koster coordinó la definición del estándar transput . El modelo incluía tres canales estándar: stand in
, stand out
, y stand back
.
En el lenguaje de programación C , los flujos de entrada, salida y error estándar se adjuntan a los descriptores de archivo Unix existentes 0, 1 y 2 respectivamente. [6] En un entorno POSIX, se deben utilizar las definiciones de < unistd.h > STDIN_FILENO , STDOUT_FILENO o STDERR_FILENO en lugar de los números mágicos . También se proporcionan los punteros de archivo stdin , stdout y stderr .
Ken Thompson (diseñador e implementador del sistema operativo Unix original) modificó sort en la versión 5 de Unix para aceptar "-" como representación de la entrada estándar, lo que se extendió a otras utilidades y se convirtió en parte del sistema operativo como un archivo especial en la versión 8. Los diagnósticos fueron parte de la salida estándar hasta la versión 6 , después de la cual Dennis M. Ritchie creó el concepto de error estándar. [7]
En Java , los flujos estándar se denominan System.in
(para stdin), System.out
(para stdout) y System.err
(para stderr). [8]
public static void main ( String args [] ) { try { BufferedReader br = new BufferedReader ( new InputStreamReader ( System . in )); String s = br . readLine (); double number = Double . parseDouble ( s ); System . out . println ( "El número es:" + number ); } catch ( Exception e ) { System . err . println ( "Error:" + e . getMessage ()); } }
En C# y otros lenguajes .NET , los flujos estándar se denominan System.Console.In
(para stdin), System.Console.Out
(para stdout) y System.Console.Error
(para stderr). [9] Las capacidades básicas de lectura y escritura para los flujos stdin y stdout también son accesibles directamente a través de la clase System.Console
(por ejemplo, System.Console.WriteLine()
se pueden usar en lugar de System.Console.Out.WriteLine()
).
System.Console.In
, System.Console.Out
y System.Console.Error
son objetos System.IO.TextReader
(stdin) y System.IO.TextWriter
(stdout, stderr) que solo permiten el acceso a los flujos estándar subyacentes en forma de texto. El acceso binario completo a los flujos estándar debe realizarse a través de los System.IO.Stream
objetos devueltos por System.Console.OpenStandardInput()
, System.Console.OpenStandardOutput()
y System.Console.OpenStandardError()
respectivamente.
// Ejemplo de C# public static int Main ( string [ ] args ) { try { string s = System.Console.In.ReadLine ( ) ; double number = double.Parse ( s ) ; System.Console.Out.WriteLine ( " El número es : { 0 : F3 } " , number ) ; return 0 ; // Si Parse() generó una excepción } catch ( ArgumentNullException ) { System . Console . Error . WriteLine ( "¡No se ingresó ningún número!" ); } catch ( FormatException ) { System . Console . Error . WriteLine ( "¡El valor especificado no es un número válido!" ); } catch ( OverflowException ) { System . Console . Error . WriteLine ( "¡El número especificado es demasiado grande!" ); } devolver - 1 ; }
' Ejemplo de Visual Basic .NETFunción pública Main () como entero Intentar Dim s como String = System . Console . [ In ] . ReadLine () Dim número como Double = Double . Parse ( s ) System . Console . Out . WriteLine ( "El número es: {0:F3}" , número ) Devuelve 0 ' Si Parse() lanzó una excepción Catch ex As System . ArgumentNullException System . Console . [ Error ] . WriteLine ( "¡No se ingresó ningún número!" ) Catch ex2 As System . FormatException System . Console . [ Error ] . WriteLine ( "¡El valor especificado no es un número válido!" ) Catch ex3 As System . OverflowException System . Console . [ Error ] . WriteLine ( "¡El número especificado es demasiado grande!" ) End Try Retorno - 1 Función final
Al aplicar la System.Diagnostics.Process
clase, se pueden utilizar las propiedades StandardInput
de instancia , StandardOutput
y StandardError
de esa clase para acceder a los flujos estándar del proceso.
El siguiente ejemplo, escrito en Python , muestra cómo redirigir la entrada estándar tanto a la salida estándar como a un archivo de texto.
#!/usr/bin/env pythonimportar sistema# Guarda la salida estándar actual para que podamos revertir sys.stdout# después de que completemos nuestra redirecciónstdin_fileno = sys . stdinstdout_fileno = sys . stdout# Redirigir sys.stdout al archivosys . stdout = open ( "miarchivo.txt" , "w" )Ctrl = 0para entradas en stdin_fileno : ctrs = cadena ( ctr ) # Imprime en la salida estándar redirigida () sys . stdout . write ( ctrs + ") esto es para el redireccionado --->" + inps + " \n " ) # Imprime en el controlador de salida estándar guardado real stdout_fileno . write ( ctrs + ") esto es al actual --->" + inps + " \n " ) Ctrl = Ctrl + 1# Cerrar el archivosys . stdout . close ()# Restaurar sys.stdout a nuestro antiguo controlador de archivos guardadosys . stdout = número_archivo_stdout
Las interfaces gráficas de usuario (GUI) no siempre hacen uso de los flujos estándar; lo hacen cuando las GUI son envoltorios de scripts subyacentes y/o programas de consola, por ejemplo, la GUI del administrador de paquetes Synaptic , que envuelve los comandos apt en Debian y/o Ubuntu. Las GUI creadas con herramientas de scripts como Zenity y KDialog por el proyecto KDE [10] hacen uso de stdin, stdout y stderr, y se basan en scripts simples en lugar de una GUI completa programada y compilada en C/C++ usando Qt , GTK u otro marco de widgets propietario equivalente.
El menú Servicios , tal como se implementó en NeXTSTEP y Mac OS X , también es análogo a los flujos estándar. En estos sistemas operativos, las aplicaciones gráficas pueden proporcionar funcionalidad a través de un menú para todo el sistema que opera sobre la selección actual en la GUI, sin importar en qué aplicación se encuentre.
Algunos programas GUI, principalmente en Unix, aún escriben información de depuración en la entrada de error estándar. Otros (como muchos reproductores multimedia de Unix) pueden leer archivos desde la entrada estándar. Los programas populares de Windows que abren una ventana de consola independiente además de sus ventanas GUI son los emuladores pSX y DOSBox .
El servidor GTK puede utilizar stdin como interfaz de comunicación con un programa interpretado para realizar una GUI.
El paradigma del Administrador de interfaz Common Lisp "presenta" elementos GUI enviados a un flujo de salida extendido.