2.7.- Redirecciones

UNIX está basado en una idea muy simple pero muy útil: Tratar todos las entrada y salidas como streams (flujos) de bytes. Cada programa va a tener asociadas siempre una entrada estándar (por  defecto el teclado), una salida estándar (por defecto la consola), y una salida de errores estándar (por defecto también la consola). Si queremos, podemos cambiar la entrada estándar para que el programa reciba datos de un fichero usando el operador de redirección >. Por ejemplo el comando cat, si no recibe argumentos, lee del teclado por la entrada estándar y lo pasa a la salida estándar:

 cat1

Una redirección consiste en trasladar la información de un tipo a otro, por ejemplo de la salida estándar a la entrada estándar o del error estándar a la salida estándar. Esto lo logramos usando el símbolo >. Por ejemplo, para redireccionar la salida de un comando y volcarla a un archivo bastaría con ejecutar:

ls -l > MiDirectorio.txt

cat2

Como podemos ver al hacer un listado vemos que se ha creado un archivo llamado MiDirectorio.txt con el contenido del resultado dado por el comando ls -l, si lo listamos con el comando cat vemos el contenido del archivo creado.

cat3

Sin embargo, cada vez que ejecutemos ese comando el contenido de MiDirectorio.txt será reemplazado por la salida del comando ls. Si queremos agregar la salida del comando al archivo, en lugar de reemplazarla, entonces ejecutamos:

cat5

El resultado sería:

cat4

 Además de la salida estándar, también podemos redireccionar el error estándar y la entrada estándar. Si queremos forzar a que un programa nos imprima en pantalla los errores que consiga durante su ejecución podemos redireccionar el error estándar hacia la salida estándar. Eso lo logramos ejecutando:

cat6

tipos_salida

La tabla de arriba explica que Linux identifica a cada tipo con un número. El tipo 2 es el error estándar y el tipo 1 es la salida estándar. En los ejemplos previos no tuvimos la necesidad de especificar el tipo 1 porque la terminal lo asume pero pudimos expresarlos explícitamente de la siguiente manera:

cat8

El comando wc nos muestra el incremento de las líneas añadidas gracias a la redirección >> de ls.

También podemos hacer algo muy común en la administración de sistemas, descartar el error estándar de un proceso. Para eso ejecutamos:

error1

O podemos descartar su salida estándar:

error2

Redirección de las salidas en escritura

La redirección en escritura nos permite enviar impresiones vinculadas a un descriptor en concreto, no al terminal, sino a un archivo.

 El nombre del archivo se expresa con ruta relativa o absoluta. En caso de que el archivo no existiese, dicho archivo sería creado. Si el archivo existe se sobrescribirá.

Veamos por ejemplo como recuperar el resultado del comando ls en el archivo resumen:

Con la redirección doble podemos concatenar los mensajes resultantes de un comando al contenido de un archivo existente.

Sintaxis:

comando 1>> archivo
o
comando >> archivo

Si el archivo no existe, se crea. Si el archivo ya existe, se abre en modo adición.

A nuestro fichero “resumen” le vamos a añadir el resultado del comando date al final.

Salida de error estándar

Sintaxis:

comando 2> archivo

En la redirección de la salida de error estándar, los resultados van a parar a la pantalla…

… y los mensajes de error van al archivo “error”.

Redirección doble

La redirección doble permite concatenar los mensajes de error de un comando al contenido de un archivo existente.

Sintaxis:

comando 2>> archivo

 Salida estándar y salida de error estándar

Podemos redirigir múltiples descriptores de una misma línea de comandos.

comando 1> archivo_a 2> archivo_b
o
comando 2> archivo_a 1> archivo_b

Eliminar las impresiones por pantalla

Todas las plataformas Unix/Linux poseen un archivo especial llamado /dev/null que nos permite hacer desaparecer las impresiones por pantalla. Este archivo se crea como un periférico y no tiene contenido. Por lo tanto, se puede considerar que está siempre vacio.

 Mecanismo interno con un comando externo

Es el shell hijo que se encarga de las redirecciones:

En la primera etapa las redirecciones se establecen por el shell hijo:

Mecanismo interno de las redirecciones en escritura.

En la segunda etapa el shell hijo se reemplaza por el comando find que hereda la tabla de los descriptores de archivo del shell.

Mecanismo interno de las redirecciones en escritura.

Mecanismo interno con un comando interno

 Un comando interno se ejecuta por el shell actual. Este último se gestiona el mismo las redirecciones. Para ello, se guarda una copia de las asociaciones descriptor-archivo actuales, conecta los descriptores a los archivos pedidos, ejecuta el comando y finalmente restaura el entorno descriptor-archivo anterior.

Redirección de la entrada estándar

La redirección de la entrada estándar concierne a los comandos que usan el descriptor 0, es decir, aquellos que esperan una entrada de datos por el teclado.

El comando mail lee la entrada estándar hasta la recepción de un final de archivo (teclas ^d). Los datos que introduzcamos serán enviados al buzón de atika.

Si deseamos hacer leer al comando mail, desde el contenido de un archivo, es suficiente conectar el descriptor 0 al archivo deseado.

Sintaxis:

o lo que es lo mismo

Ejemplo:

Veamos, en la primera etapa la redirección se establece por el shell hijo.

Mecanismo interno de redirección en lectura.

En la etapa segunda, el comando mail realiza una lectura del descriptor 0.

Mecanismo interno de la redirección en lectura.

Redirecciones avanzadas

Redirigir los descriptores 1 y 2 hacia le mismo.

 Para enviar la salida estándar y la salida de error estándar hacia el mismo archivo, es necesario emplear una sintaxis particular.

Sintaxis incorrectas

El problema no reside en el hecho de abrir dos veces el mismo archivo (lo que es perfectamente legal dentro del mismo proceso), sino en que hay un offset (posición actual dentro del archivo) asociado a cada apertura.

Veamos las consecuencias:

  • La secuencia de resultados en el archivo no será forzosamente representativa del orden en el que se desarrollan los eventos.
  • Los resultados emitidos a través de los descriptores 1 Y 2 corren el riesgo de sufrir superposiciones.

Sea el siguiente comando:

Veamos el esquema de como se comporta el mecanismo interno asociado al comando de arriba:

Primera etapa.

Gestión del procesamiento en las redirecciones. Primera etapa.

Tratamiento de la redirección 1>resu:

El shell abre el archivo resu (el archivo se crea con un tamaño igual a 0) y lo asocia al descriptor 1 (1, 2, 3, 4, 5). Cuando un proceso abre un archivo, siempre hay un registro asignado en la tabla de archivos abiertos del núcleo (2) (ésta recoge todas las aperturas de archivo del sistema en un momento dado). El registro contiene el modo de apertura del archivo (en este caso, escritura), así como la posición actual dentro del archivo (en este caso, la escritura en el descriptor 1 empezará en el inicio del archivo). La posición (1) de la tabla de descriptores de archivos del proceso contiene un puntero (p2) hacia el registro de la tabla de archivos abiertos.

Tratamiento de la redirección 2>resu:

El shell abre nuevamente el archivo resu en escritura (6, 7, 3, 4, 5) (el fichero es sobrescrito, lo que no representa un problema puesto que el tamaño era o) y lo asocia al descriptor 2. Un nuevo registro se crea en la tabla de archivos abiertos (p3) (7). Las operaciones se escritura posteriores en el descriptor 2 se harán a partir del inicio del archivo.

 Segunda etapa

Gestión del posicionamiento en las redirecciones. Segunda etapa.

El shell se reemplaza por el comando find (véase la figura de arriba) que hereda la tabla de descriptores  de archivos. Veamos la simulación del comando find:

  • find envia al descriptor 1 un mensaje resultado de 20 bytes (1, 2, 3, …);
  • estos 20 bytes se escriben a partir de la posición 0 (2). Después, el valor del offset es 20 (3) que será utilizado en la próxima escritura en la salida estándar;
  • el archivo crece 20 bytes (4);
  • find envía al descriptor 2 un mensaje de error de 10 bytes (5);
  • éstos se escribirán al inicio del archivo (el offset del descriptor 2 vale 0 (7)), y por lo tanto sobre escribirán el mensaje escrito anteriormente (8). El offset de la salida de error pasará a ser 10 (7).

En conclusión, el archivo es utilizable porque los mensajes de error y resultado se superponen.

Sintaxis correctas

Para obtener un resultado correcto, hay que usar una de las dos sintaxis siguientes:

Veamos el comportamiento del siguiente comando:

La siguiente figura representa el mecanismo interno generado por la primera sintaxis:

Redirección de los dos descriptores en un mismo archivo.

 Tratamiento de la redirección 1> resu:

Utiliza el mismo mecanismo que el anterior, o sea, creación del archivo resu, asignación de un registro en la tabla de archivos abiertos, offset a 0 (1).

Tratamiento de la redirección 2>&1:

Podemos decir para una mejor comprensión que el descriptor 2 está redirigido al descriptor 1 (representado por &1). el concepto importante que hay que comprender es que el shell, gracias a esta sintaxis, duplica (2) simplemente la dirección del descriptor 1 en el descriptor 2. Por lo tanto, los dos descriptores apuntan (p2) al mismo registro de la tabla de archivos abiertos, y por consiguiente, comparten el mismo offset. No hay asignación de un nuevo registro en la tabla de archivos abiertos del núcleo. Las escrituras posteriores, ya sean emitidas a través de la salida estándar o de la salida de error estándar, se servirán del mismo offset.

La sintaxis 1> resu 2>&1 no es equivalente a 2>&1 1>resu. En el segundo caso la salida de error estándar se redirige hacia la salida estándar, es decir, el terminal. Después, la salida estándar se asocia al archivo resu. Llegando a la conclusión que los mensajes de error son dirigidos hacia el terminal y los mensajes de resultado hacia el archivo resu.

La redirección doble en lectura

Son usados principalmente en scripts de shell. Permite conectar la entrada estándar de un comando a una porción del script.

 Primera sintaxis

Segunda sintaxis

El símbolo situado después de los caracteres << es una declaración de etiqueta. Esta etiqueta la usaremos para declarar el final de los datos que tendrá que leer el comando. Las líneas insertadas entre las dos palabras ETIQUETA serán enviadas a la entrada estándar del comando.

Ejemplo:

  • en la primera sintaxis la etiqueta debe estar pegada obligatoriamente al margen izquierdo de los símbolos <<

  • en la segunda sintaxis, el hecho de colocar un carácter delante de la etiqueta permite al usuario poner la última etiqueta después de una o varias tabulaciones;
  • las etiquetas tienen que estar seguidas inmediatamente de un salto de línea.

Cierre de un descriptor

 

Anuncios