Flujos estándar - Standard streams

En la programación de computadoras , los flujos estándar son canales de comunicación de entrada y salida interconectados entre un programa de computadora y su entorno cuando comienza la 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 de sistema conectada físicamente (entrada a través del teclado, salida a través del monitor), pero los flujos estándar lo abstraen. Cuando se ejecuta un comando a través de un shell interactivo , las transmisiones normalmente se conectan al terminal de texto en el que se ejecuta el shell, pero se pueden cambiar con una redirección o una canalización . De manera más general, un proceso hijo hereda los flujos estándar de su proceso padre .

Solicitud

Image
Los flujos estándar para entrada, salida y error.

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 . En muchos sistemas modernos, el flujo de errores estándar de un programa se redirige a un archivo de registro, generalmente con fines de análisis de errores.

Los flujos se pueden usar para encadenar aplicaciones, lo que significa que el flujo de salida de un programa se puede redirigir para que sea el flujo de entrada a 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 esta razón a menudo se denomina carácter de canalización . Un ejemplo bien conocido es el uso de una aplicación de paginación , como más , que proporciona al usuario control sobre la visualización del flujo de salida en la pantalla.

Fondo

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 que era necesario para obtener el control de la configuración del entorno, acceder a una tabla de archivos local, determinar el conjunto de datos previsto, y el hardware de mango correctamente en el caso de un lector de tarjetas perforadas , unidad de cinta magnética , disco , impresora en línea , tarjetas perforadas , o terminal interactivo.

Uno de los varios 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. Los sistemas operativos más antiguos imponían al programador una estructura de registro y, con frecuencia , una semántica de datos y un control de dispositivos no ortogonales . 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 como desee y no es necesario, y no puede declarar fácilmente su recuento o agrupación.

Otro avance de Unix fue asociar automáticamente la entrada y la salida al teclado del terminal y la pantalla del terminal, respectivamente, de forma predeterminada: el programa (y el programador) no hicieron absolutamente nada para establecer la entrada y la salida para un programa típico de entrada-proceso-salida (a menos que eligiera un paradigma diferente). Por el contrario, los sistemas operativos anteriores generalmente requerían algún lenguaje de control de trabajo, a menudo complejo , para establecer conexiones, o el programa tenía que orquestar la carga equivalente.

Dado que Unix proporcionaba flujos estándar, el entorno de ejecución de Unix C también estaba obligado a admitirlo. Como resultado, la mayoría de los entornos de ejecución de C (y los descendientes de C ), independientemente del sistema operativo, proporcionan una funcionalidad equivalente.

Entrada estándar (stdin)

La entrada estándar es una secuencia desde la que 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 entrada de flujo. 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.

A menos que se redirija , la entrada estándar se hereda del proceso principal. En el caso de un shell interactivo, generalmente está asociado con el teclado .

El descriptor de archivo para la entrada estándar es 0 (cero); la definición de POSIX <unistd.h> es STDIN_FILENO; la correspondiente variable C <stdio.h> es FILE* stdin; de manera similar, la variable C ++ <iostream> es std::cin.

Salida estándar (stdout)

La salida estándar es una secuencia en la 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 resultados. Por ejemplo, el comando de cambio de nombre de archivo (llamado mv , move o ren ) no dice nada sobre el éxito.

A menos que se redirija , la salida estándar se hereda del proceso principal. En el caso de un shell interactivo, suele ser el terminal de texto que inició el programa.

El descriptor de archivo para la salida estándar es 1 (uno); la definición de POSIX <unistd.h> es STDOUT_FILENO; la correspondiente variable C <stdio.h> es FILE* stdout; de manera similar, la variable C ++ <iostream> es std::cout.

Error estándar (stderr)

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 de semipredicado , lo que permite distinguir la salida y los errores, y es análogo a una función que devuelve un par de valores; consulte Problema de semipredicado: retorno de valores múltiples . El destino habitual es el terminal de texto que inició el programa para proporcionar la mejor oportunidad 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 canalización se redirige a la entrada del siguiente programa, pero los errores de cada programa siguen yendo directamente a la terminal de texto.

Es aceptable y normal dirigir la salida estándar y el error estándar al mismo destino, como el terminal de texto. Los mensajes aparecen en el mismo orden en que los escribe el programa, a menos que esté involucrado el almacenamiento en búfer . Por ejemplo, en situaciones comunes, el flujo de error estándar no tiene búfer, pero el flujo de salida estándar tiene búfer de línea; en este caso, el texto escrito con error estándar más tarde puede aparecer en el terminal antes, si el búfer de flujo de salida estándar aún no está lleno.

El descriptor de fichero para el error estándar se define por POSIX como 2 (dos); el archivo de encabezado <unistd.h> proporciona el símbolo STDERR_FILENO; la variable C <stdio.h> correspondiente es FILE* stderr. El encabezado estándar de C ++ <iostream> proporciona dos variables asociadas con esta secuencia: std::cerry std::clog, la primera no tiene búfer y la última usa el mismo mecanismo de almacenamiento en búfer que todas las demás secuencias de C ++.

Los shells estilo Bourne permiten redirigir el error estándar al mismo destino al que se dirige la salida estándar usando

 2>&1

Los shells estilo csh permiten redirigir el error estándar al mismo destino al que se dirige la salida estándar usando

 >&

El error estándar se agregó a Unix en la década de 1970 después de que varias corridas de fotocomposición desperdiciadas terminaron con mensajes de error que se componían en lugar de mostrarse en el terminal del usuario.

Cronología

Década de 1950: Fortran

Fortran tiene el equivalente a los descriptores de archivos de Unix: por convención, muchas implementaciones de Fortran usan números de unidad UNIT=5para stdin, UNIT=6stdout y UNIT=0stderr. En Fortran-2003, la intrínseca ISO_FORTRAN_ENVmódulo fue estandarizada para incluir las constantes con nombre INPUT_UNIT, OUTPUT_UNITy ERROR_UNITpara especificar portable los números de unidad.

! FORTRAN 77 example
      PROGRAM MAIN
        INTEGER NUMBER
        READ(UNIT=5,*) NUMBER
        WRITE(UNIT=6,'(A,I3)') ' NUMBER IS: ',NUMBER
      END
! Fortran 2003 example
program main
  use iso_fortran_env
  implicit none
  integer :: number
  read (unit=INPUT_UNIT,*) number
  write (unit=OUTPUT_UNIT,'(a,i3)') 'Number is: ', number
end program

1960: ALGOL 60

ALGOL 60 fue criticado por no tener acceso estándar a los archivos.

1968: ALGOL 68

Las instalaciones de entrada y salida de ALGOL 68 se denominaron colectivamente transput. Koster coordinó la definición del estándar de transput . El modelo incluyó tres canales estándar: stand in, stand out, y stand back.

Ejemplo
# ALGOL 68 example #
main:(
  REAL number;
  getf(stand in,($g$,number));
  printf(($"Number is: "g(6,4)"OR "$,number)); # OR #
  putf(stand out,($" Number is: "g(6,4)"!"$,number));
  newline(stand out)
)
Aporte: Producción:
3.14159
Number is: +3.142 OR Number is: +3.142!

Década de 1970: C y Unix

En el lenguaje de programación C , los flujos estándar de entrada, salida y error se adjuntan a los descriptores de archivo Unix existentes 0, 1 y 2 respectivamente. En un entorno POSIX , las definiciones de < unistd.h > STDIN_FILENO , STDOUT_FILENO o STDERR_FILENO deben usarse en lugar de 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ó el ordenamiento en la versión 5 de Unix para aceptar "-" como una entrada estándar, 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 lo cual Dennis M. Ritchie creó el concepto de error estándar.

1995: Java

En Java , las secuencias estándar se denominan System.in(para stdin), System.out(para stdout) y System.err(para stderr).

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("Number is:" + number);
    } catch (Exception e) {
        System.err.println("Error:" + e.getMessage());
    }
}

Década de 2000: .NET

En C # y otros lenguajes .NET , las secuencias estándar se denominan System.Console.In(para stdin), System.Console.Out(para stdout) y System.Console.Error(para stderr). 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.Outy System.Console.Errorson objetos System.IO.TextReader(stdin) y System.IO.TextWriter(stdout, stderr), que solo permiten el acceso a los flujos estándar subyacentes sobre una base de texto. Acceso binaria completa de los flujos estándares debe ser realizada a través de los System.IO.Streamobjetos devueltos por System.Console.OpenStandardInput(), System.Console.OpenStandardOutput()y System.Console.OpenStandardError()respectivamente.

// C# example
public static int Main(string[] args)
{
    try {
        string s = System.Console.In.ReadLine();
        double number = double.Parse(s);
        System.Console.Out.WriteLine("Number is: {0:F3}", number);
        return 0;

    // If Parse() threw an exception
    } catch (ArgumentNullException) { 
        System.Console.Error.WriteLine("No number was entered!");
    } catch (FormatException) {
        System.Console.Error.WriteLine("The specified value is not a valid number!");
    } catch (OverflowException) {
        System.Console.Error.WriteLine("The specified number is too big!");
    }

    return -1;
}
' Visual Basic .NET example

Public Function Main() As Integer
    Try
        Dim s As String = System.Console.[In].ReadLine()
        Dim number As Double = Double.Parse(s)
        System.Console.Out.WriteLine("Number is: {0:F3}", number)
        Return 0

    ' If Parse() threw an exception
    Catch ex As System.ArgumentNullException
        System.Console.[Error].WriteLine("No number was entered!")
    Catch ex2 As System.FormatException
        System.Console.[Error].WriteLine("The specified value is not a valid number!")
    Catch ex3 As System.OverflowException
        System.Console.[Error].WriteLine("The specified number is too big!")
    End Try

    Return -1
End Function

Cuando se aplica la System.Diagnostics.Process clase uno puede utilizar la instancia de propiedades StandardInput , StandardOutputy StandardErrorde esa clase de acceso a los flujos estándares del proceso.

GUI

Las interfaces gráficas de usuario (GUI) no siempre utilizan 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 scripting como Zenity y KDialog por el proyecto KDE 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 widget propietario equivalente estructura.

El menú Servicios , implementado en NeXTSTEP y Mac OS X , también es análogo a las transmisiones estándar. En estos sistemas operativos, las aplicaciones gráficas pueden proporcionar funcionalidad a través de un menú de todo el sistema que opera en la selección actual en la GUI, sin importar en qué aplicación.

Algunos programas de GUI, principalmente en Unix, todavía escriben información de depuración en errores estándar. Otros (como muchos reproductores multimedia Unix) pueden leer archivos de la entrada estándar. Los programas populares de Windows que abren una ventana de consola separada además de sus ventanas GUI son los emuladores pSX y DOSBox .

GTK-server puede usar stdin como interfaz de comunicación con un programa interpretado para realizar una GUI.

El paradigma Common Lisp Interface Manager "presenta" elementos GUI enviados a un flujo de salida extendido.

Ver también

Referencias

Fuentes

enlaces externos