103.4 Lección 1
Certificación: |
LPIC-1 (101) |
---|---|
Versión: |
5.0 |
Tema: |
103 Comandos GNU y Unix |
Objetivo: |
103.4 Usar flujos, tuberías y redireccionamientos |
Lección: |
1 de 2 |
Introducción
Todos los programas de computadora siguen el mismo principio general: los datos recibidos de alguna fuente se transforman para generar un resultado inteligible. En el contexto de shell de Linux, la fuente de datos puede ser un archivo local, un archivo remoto, un dispositivo (como un teclado), etc. La salida del programa generalmente se representa en una pantalla, pero también es común almacenar los datos de salida en un sistema de archivos local, enviarlo a un dispositivo remoto, reproducirlo a través de altavoces de audio, etc.
Los sistemas operativos inspirados en Unix, como Linux, ofrecen una gran variedad de métodos de entrada/salida. En particular, el método de descriptores de archivos permite asociar dinámicamente números enteros con canales de datos, de modo que un proceso pueda hacer referencia a ellos como sus flujos de datos de entrada/salida.
Los procesos estándar de Linux tienen
tres canales de comunicación abiertos de
manera predeterminada: el canal de entrada
estándar (la mayoría de las veces llamado
simplemente stdin), el canal
de salida estándar (stdout)
y el canal de error estándar (stderr).
Los descriptores numéricos de archivos
asignados a estos canales son 0
a stdin, 1
a stdout y 2
a stderr. Los canales de comunicación
también son accesibles a través de los
dispositivos especiales /dev/stdin
,
/dev/stdout
y /dev/stderr
.
Estos tres canales de comunicación estándar permiten a los programadores escribir código que lee y escribe datos sin preocuparse por el tipo de medio del que proviene o al que va. Por ejemplo, si un programa necesita un conjunto de datos como entrada, solo puede solicitar datos de la entrada estándar y lo que se esté utilizando como entrada estándar proporcionará esos datos. Del mismo modo, el método más simple que un programa puede usar para mostrar su salida es escribirlo en la salida estándar. En una sesión de shell estándar, el teclado se define como stdin y la pantalla del monitor se define como stdout y stderr.
El shell Bash tiene la capacidad de reasignar los canales de comunicación al cargar un programa. Permite, por ejemplo, anular la pantalla como salida estándar y usar un archivo en el sistema de archivos local como stdout.
Redireccionamientos
La reasignación del descriptor de
archivo de un canal en el entorno de
shell se denomina redirect.
Una redirección se define mediante un
caracter especial dentro de la línea de
comandos. Por ejemplo, para redirigir la
salida estándar de un proceso a un
archivo, el símbolo mayor que
>
se coloca al final del
comando y sigue la ruta al archivo que
recibirá la salida redirigida:
$ cat /proc/cpuinfo >/tmp/cpu.txt
Por defecto, solo se redirige el
contenido que llega a stdout. Eso sucede
porque el valor numérico del descriptor
de archivo debe especificarse justo
antes del símbolo mayor que y, cuando no
se especifica, Bash redirige la salida
estándar. Por lo tanto, usar >
es equivalente a usar 1>
(el valor del descriptor de archivo
stdout es 1
).
Para capturar el contenido de stderr,
se debe usar la redirección 2>
en su lugar. La mayoría de los programas
de línea de comandos envían información
de depuración y mensajes de error al
canal de error estándar. Es posible, por
ejemplo, capturar el mensaje de error
provocado por un intento de leer un
archivo inexistente:
$ cat /proc/cpu_info 2>/tmp/error.txt $ cat /tmp/error.txt cat: /proc/cpu_info: No such file or directory
Tanto stdout como stderr se redirigen
al mismo objetivo con &>
o >&
. Es importante
no colocar ningún espacio al lado del
ampersand, de lo contrario, Bash lo
tomará como la instrucción para ejecutar
el proceso en segundo plano y no
realizará la redirección.
El destino debe ser una ruta a un
archivo en el que se pueda escribir,
como /tmp/cpu.txt
, o un
descriptor de archivo editable. Un
objetivo de descriptor de archivo está
representado por un ampersand seguido
del valor numérico del descriptor de
archivo. Por ejemplo, 1>&2
redirige stdout a stderr. Para hacer lo
contrario, de stderr a stdout, se debe
usar 2>&1
en su
lugar.
Aunque no es muy útil, dado que hay una
forma más corta de hacer la misma tarea,
es posible redirigir stderr a stdout y
luego redirigirlo a un archivo. Por
ejemplo, una redirección para escribir
stderr y stdout en un archivo llamado log.txt
puede escribirse como >log.txt
2>&1
. Sin embargo, la
razón principal para redirigir stderr a
stdout es permitir el análisis de
mensajes de error y depuración. Es
posible redirigir la salida estándar de
un programa a la entrada estándar de
otro, pero no es posible redirigir
directamente el error estándar a la
entrada estándar de otro programa. Por
lo tanto, los mensajes del programa
enviados a stderr primero deben
redirigirse a stdout para que otros
stdin puedan leerlos.
Para descartar la salida de un comando,
su contenido se puede redirigir al
archivo especial /dev/null
.
Por ejemplo, >log.txt
2>/dev/null
guarda el
contenido de stdout en el archivo log.txt
y descarta el stderr. El archivo /dev/null
puede ser escrito por cualquier usuario
pero no se pueden recuperar datos, ya
que no se almacenan en ningún lado.
Se presenta un mensaje de error si el
destino especificado no se puede
escribir (si la ruta apunta a un
directorio o un archivo de solo lectura)
y no se realiza ninguna modificación en
el destino. Sin embargo, una redirección
de salida sobrescribe el destino
existente sin ninguna confirmación. Los
archivos se sobrescriben mediante
redireccionamientos de salida a menos
que la opción Bash noclobber
esté habilitada, lo que se puede hacer
para la sesión actual con el comando set
-o noclobber
o set -C
:
$ set -o noclobber $ cat /proc/cpu_info 2>/tmp/error.txt -bash: /tmp/error.txt: cannot overwrite existing file
Para desactivar la opción noclobber
para la sesión actual, ejecute set
+o noclobber
o set +C
.
Para que la opción noclobber
sea persistente, debe incluirse en el
perfil Bash del usuario o en el perfil
de todo el sistema.
Incluso con la opción noclobber
habilitada, es posible agregar datos
redirigidos al contenido existente. Esto
se logra con una redirección escrita con
dos símbolos mayores que >>
:
$ cat /proc/cpu_info 2>>/tmp/error.txt $ cat /tmp/error.txt cat: /proc/cpu_info: No such file or directory cat: /proc/cpu_info: No such file or directory
En el ejemplo anterior, el nuevo
mensaje de error se agregó al existente
en el archivo /tmp/error.txt
.
Si el archivo aún no existe, se creará
con los nuevos datos.
La fuente de datos de la entrada
estándar de un proceso también se puede
reasignar. El símbolo menor que <
se usa para redirigir el contenido de un
archivo al stdin de un proceso. En este
caso, los datos fluyen de derecha a
izquierda: se supone que el descriptor
reasignado es 0 a la izquierda del
símbolo menor que y el origen de datos
(una ruta a un archivo) debe estar a la
derecha del símbolo menor. El comando uniq
,
como la mayoría de las utilidades de
línea de comandos para procesar texto,
acepta los datos enviados a stdin por
defecto:
$ uniq -c </tmp/error.txt 2 cat: /proc/cpu_info: No such file or directory
La opción -c
hace que uniq
muestre cuántas veces aparece una línea
repetida en el texto. Como se suprimió
el valor numérico del descriptor de
archivo redirigido, el comando de
ejemplo es equivalente a uniq -c
0</tmp/error.txt
. Usar un
descriptor de archivo que no sea 0
en una redirección de entrada solo tiene
sentido en contextos específicos, porque
es posible que un programa solicite
datos en los descriptores de archivo 3
,
4
, etc. De hecho, los
programas pueden usar cualquier número
entero por encima de 2 como nuevos
descriptores de archivo para
entrada/salida de datos. Por ejemplo, el
siguiente código C lee los datos del
descriptor de archivo 3
y
simplemente lo replica en el descriptor
de archivo 4
:
Note
|
El programa debe manejar dichos descriptores de archivo correctamente, de lo contrario podría intentar una operación de lectura o escritura no válida y bloquearse. |
#include <stdio.h> int main(int argc, char **argv){ FILE *fd_3, *fd_4; // Open file descriptor 3 fd_3 = fdopen(3, "r"); // Open file descriptor 4 fd_4 = fdopen(4, "w"); // Read from file descriptor 3 char buf[32]; while ( fgets(buf, 32, fd_3) != NULL ){ // Write to file descriptor 4 fprintf(fd_4, "%s", buf); } // Close both file descriptors fclose(fd_3); fclose(fd_4); }
Para probarlo, guarde el código de
muestra como fd.c
y
compílelo con gcc -o fd fd.c
.
Este programa necesita que estén
disponibles los descriptores de archivo
3 y 4 para poder leerlos y escribirlos.
Como ejemplo, el archivo creado
previamente /tmp/error.txt
se puede utilizar como fuente del
descriptor de archivo 3
y
el descriptor de archivo 4
se puede redirigir a stdout:
$ ./fd 3</tmp/error.txt 4>&1 cat: /proc/cpu_info: No such file or directory cat: /proc/cpu_info: No such file or directory
Desde la perspectiva del programador,
el uso de descriptores de archivos evita
tener que lidiar con el análisis de
opciones y las rutas del sistema de
archivos. El mismo descriptor de archivo
puede incluso usarse como entrada y
salida. En este caso, el descriptor de
archivo se define en la línea de
comandos con símbolos menores y mayores
que, como en 3<>/tmp/error.txt
.
Here Document y Here String
Otra forma de redirigir la entrada
involucra los métodos Here Document
y Here String. La redirección
de documentos Here permite
escribir texto de varias líneas que se
utilizará como contenido redirigido. Dos
símbolos menor que <<
indican una redirección de Here
Document:
$ wc -c <<EOF > How many characters > in this Here document? > EOF 43
A la derecha de los dos símbolos menor
que <<
se encuentra
el término final EOF
. El
modo de inserción finalizará tan pronto
como se ingrese una línea que contenga
solo el término final. Se puede usar
cualquier otro término como término
final, pero es importante no poner
caracteres en blanco entre el símbolo
menor que y el término final. En el
ejemplo anterior, las dos líneas de
texto se enviaron al stdin del comando wc
-c
, que muestra el recuento de
caracteres. Al igual que con los
redireccionamientos de entrada para
archivos, se supone el stdin (descriptor
de archivo 0
) si se
suprime el descriptor de archivo
redirigido.
El método Here String es muy similar al método de Here Document, pero solo para una línea:
$ wc -c <<<"How many characters in this Here string?" 41
En este ejemplo, la cadena a la derecha
de los tres signos menor que se envía al
stdin de wc -c
, que cuenta
el número de caracteres. Las cadenas que
contienen espacios deben estar entre
comillas, de lo contrario, solo la
primera palabra se usará como la cadena
Here y las restantes se pasarán como
argumentos al comando.
Ejercicios Guiados
-
Además de los archivos de texto, el comando
cat
también puede trabajar con datos binarios, como enviar el contenido de un dispositivo de bloque a un archivo. Usando la redirección, ¿cómo puedecat
enviar el contenido del dispositivo/dev/sdc
al archivosdc.img
en el directorio actual?
-
¿Cuál es el nombre del canal estándar redirigido por el comando
date 1> now.txt
?
-
Después de intentar sobrescribir un archivo usando la redirección, un usuario recibe un error informando que la opción
noclobber
está habilitada. ¿Cómo se puede desactivar la opciónnoclobber
para la sesión actual?
-
¿Cuál será el resultado del comando
cat <<.>/dev/stdout
?
Ejercicios Exploratorios
-
El comando
cat /proc/cpu_info
muestra un mensaje de error porque/proc/cpu_info
no existe. El comandocat /proc/cpu_info 2>1
redirige el mensaje de error a dónde?
-
¿Será posible descartar el contenido enviado a
/dev/null
si la opciónnoclobber
está habilitada para la sesión de shell actual?
-
Sin usar
echo
, ¿cómo se podría redirigir el contenido de la variable$USER
al stdin del comandosha1sum
?
-
El kernel de Linux mantiene enlaces simbólicos en
/proc/PID/fd/
a cada archivo abierto por un proceso, donde PID es el número de identificación del proceso correspondiente. ¿Cómo podría el administrador del sistema usar ese directorio para verificar la ubicación de los archivos de registro abiertos pornginx
, suponiendo que su PID sea1234
?
-
Es posible hacer cálculos aritméticos utilizando solo comandos integrados de shell, pero los cálculos de coma flotante requieren programas específicos, como
bc
(basic calculator). Conbc
incluso es posible especificar el número de lugares decimales, con el parámetroscale
. Sin embargo,bc
acepta operaciones solo a través de su entrada estándar, generalmente ingresada en modo interactivo. Usando una cadena Here, ¿cómo puede la operación de coma flotantescale = 6; 1 / 3
enviarse a la entrada estándar debc
?
Resumen
Esta lección cubre los métodos para ejecutar un programa que redirige sus canales de comunicación estándar. Los procesos de Linux utilizan estos canales estándar como descriptores genéricos de archivos para leer y escribir datos, lo que permite cambiarlos arbitrariamente a archivos o dispositivos. La lección sigue los siguientes pasos:
-
Qué son los descriptores de archivos y el papel que juegan en Linux.
-
Los canales de comunicación estándar de cada proceso: stdin, stdout y stderr.
-
Cómo ejecutar correctamente un comando utilizando la redirección de datos, tanto para entrada como para salida.
-
Cómo usar Here Document y Here String en las redirecciones de entrada
Los comandos y procedimientos abordados fueron:
-
Operadores de redireccionamiento:
>
,<
,>>
,<<
,<<<
. -
Comandos
cat
,set
,uniq
ywc
.
Respuestas a los ejercicios guiados
-
Además de los archivos de texto, el comando
cat
también puede trabajar con datos binarios, como enviar el contenido de un dispositivo de bloque a un archivo. Usando la redirección, ¿cómo puedecat
enviar el contenido del dispositivo/dev/sdc
al archivosdc.img
en el directorio actual?$ cat /dev/sdc > sdc.img
-
¿Cuál es el nombre del canal estándar redirigido por el comando
date 1> now.txt
?Salida estándar o stdout
-
Después de intentar sobrescribir un archivo usando la redirección, un usuario recibe un error informando que la opción
noclobber
está habilitada. ¿Cómo se puede desactivar la opciónnoclobber
para la sesión actual?set +C
oset +o noclobber
-
¿Cuál será el resultado del comando
cat <<.>/dev/stdout
?Bash ingresará al modo de entrada Heredoc, luego saldrá cuando aparezca un punto en una línea por sí mismo. El texto escrito se redirigirá a stdout (impreso en la pantalla).
Respuestas a ejercicios exploratorios
-
El comando
cat /proc/cpu_info
muestra un mensaje de error porque/proc/cpu_info
no existe. El comandocat /proc/cpu_info 2>1
redirige el mensaje de error a dónde?A un archivo llamado
1
en el directorio actual. -
¿Será posible descartar el contenido enviado a
/dev/null
si la opciónnoclobber
está habilitada para la sesión de shell actual?Si.
/dev/null
es un archivo especial no afectado pornoclobber
. -
Sin usar
echo
, ¿cómo se podría redirigir el contenido de la variable$USER
al stdin del comandosha1sum
?$ sha1sum <<<$USER
-
El kernel de Linux mantiene enlaces simbólicos en
/proc/PID/fd/
a cada archivo abierto por un proceso, donde PID es el número de identificación del proceso correspondiente. ¿Cómo podría el administrador del sistema usar ese directorio para verificar la ubicación de los archivos de registro abiertos pornginx
, suponiendo que su PID sea1234
?Al emitir el comando
ls -l /proc/1234/fd
, que mostrará los objetivos de cada enlace simbólico en el directorio. -
Es posible hacer cálculos aritméticos utilizando solo comandos integrados de shell, pero los cálculos de coma flotante requieren programas específicos, como
bc
(basic calculator). Conbc
incluso es posible especificar el número de lugares decimales, con el parámetroscale
. Sin embargo,bc
acepta operaciones solo a través de su entrada estándar, generalmente ingresada en modo interactivo. Usando una cadena Here, ¿cómo puede la operación de coma flotantescale = 6; 1 / 3
se enviará a la entrada estándar debc
?$ bc <<<"scale=6; 1/3"