Los scripts de shell brindan una característica muy poderosa:la capacidad de redirigir la salida de comandos y scripts y enviarla a archivos, dispositivos o incluso como entrada a otros comandos o scripts.
Este artículo se centra en la salida de comandos y secuencias de comandos.
Tipos de salida
Los comandos y scripts en un shell pueden generar dos tipos básicos de resultados:
- SALIDA ESTÁNDAR: La salida normal de un comando/secuencia de comandos (descriptor de archivo 1)
- STDERR: La salida de error de un comando/secuencia de comandos (descriptor de archivo 2)
De forma predeterminada, STDOUT y STDERR se envían a la pantalla de su terminal.
En términos de entrada, STDIN por defecto lee la entrada del teclado (descriptor de archivo 0). Un descriptor de archivo es un identificador único para un archivo u otro recurso de E/S.
Cómo redirigir la salida del shell
Hay varias formas de redirigir la salida de los scripts y comandos de shell.
1. Redirigir STDOUT
Para los siguientes ejemplos, usaré este conjunto simple de archivos:
$ls -la file*
-rw-r--r--. 1 admin2 admin2 7 Mar 27 15:34 file1.txt
-rw-r--r--. 1 admin2 admin2 10 Mar 27 15:34 file2.txt
-rw-r--r--. 1 admin2 admin2 13 Mar 27 15:34 file3.txt
Estoy ejecutando un ls
simple comandos para ilustrar STDOUT frente a STDERR, pero el mismo principio se aplica a la mayoría de los comandos que ejecuta desde un shell.
Puedo redirigir la salida estándar a un archivo usando ls file* > my_stdout.txt
:
$ls file* > my_stdout.txt
$ cat my_stdout.txt
file1.txt
file2.txt
file3.txt
A continuación, ejecuto un comando similar, pero con un 1
antes de >
. Redirigir usando el >
la señal es lo mismo que usar 1>
para hacerlo:le digo al shell que redirija el STDOUT a ese archivo. Si omito el descriptor de archivo, STDOUT se usa de forma predeterminada. Puedo probar esto ejecutando sdiff
comando para mostrar la salida de ambos comandos uno al lado del otro:
$ls file* 1> my_other_stdout.txt
$sdiff my_stdout.txt my_other_stdout.txt
file1.txt file1.txt
file2.txt file2.txt
file3.txt file3.txt
Como puede ver, ambas salidas tienen el mismo contenido.
2. Redirigir STDERR
Ahora, ¿qué tiene de especial STDERR? Para demostrarlo, introduciré una condición de error en el ejemplo anterior con ls file* non-existing-file* > my_normal_output.txt
:
Aquí está el resultado:
ImagenAquí hay algunas observaciones de la prueba anterior:
- El resultado de los archivos existentes se envía correctamente al archivo de destino.
- El error (que aparece cuando trato de enumerar algo que no existe) se envía a la pantalla. Este es el lugar predeterminado donde se envían los errores a menos que los redirija.
[ Descargue una hoja de referencia de secuencias de comandos de Bash Shell. ]
A continuación, redirigiré la salida de error haciendo referencia explícita al descriptor de archivo 2 con ls file* non-existing-file* > my_normal_output.txt 2> my_error_output.txt:
En el ejemplo anterior:
- Los
ls
El comando no muestra el mensaje de error en la pantalla como antes. - La salida normal contiene lo que espero.
- El mensaje de error se envía a
my_error_output.txt
archivo.
3. Enviar STDOUT y STDERR al mismo archivo
Otra situación común es enviar STDOUT y STDERR al mismo archivo:
$ls file* non-existing-file* > my_consolidated_output.txt 2>&1
$ cat my_consolidated_output.txt
ls: cannot access 'non-existing-file*': No such file or directory
file1.txt
file2.txt
file3.txt
En este ejemplo, toda la salida (normal y de error) se envía al mismo archivo.
El 2>&1
construcción significa "enviar el STDERR al mismo lugar donde está enviando el STDOUT ."
4. Redirigir la salida, pero agregar el archivo
En todos los ejemplos anteriores, cada vez que redirigía alguna salida, usaba un solo >
, lo que significa "envíe algo a este archivo e inicie el archivo desde cero ." Como resultado, si el archivo de destino existe, se sobrescribe.
Si quiero añadir a un archivo existente, necesito usar >>
. Si el archivo aún no existe, se creará:
$echo "Adding stuff to the end of a file" >> my_output.txt
$cat my_output.txt
file1.txt
file2.txt
file3.txt
Adding stuff to the end of a file
5. Redirigir a otro proceso o a ninguna parte
Los ejemplos anteriores cubren la redirección de la salida a un archivo, pero también puede redirigir las salidas a otros procesos o dev/null
.
Enviar resultados a otros procesos es una de las características más poderosas de un shell. Para esta tarea, use el |
(tubería), que envía la salida de un comando a la entrada del siguiente comando:
ps -ef | grep chrome | grep -v grep | wc -l
21
El ejemplo anterior enumera mis procesos, filtra cualquiera que contenga la cadena chrome , ignora la línea sobre mi grep
y cuenta las líneas resultantes. Si quiero enviar la salida a un archivo, agrego >
y un nombre de archivo al final de la cadena.
Finalmente, aquí hay un ejemplo en el que quiero ignorar una de las salidas, STDERR:
$tar cvf my_files.tar file* more-non-existing*
file1.txt
file2.txt
file3.txt
tar: more-non-existing*: Cannot stat: No such file or directory
tar: Exiting with failure status due to previous errors
Porque el tar
El comando no encontró ningún archivo con nombres que comiencen con more-non-existing
, se muestran algunos mensajes de error al final.
Supongamos que creo algunos scripts y no me importa ver o capturar estos errores (lo sé, en la vida real, debe prevenir y manejar los errores, no solo ignorarlos):
$tar cvf my_files.tar file* more-non-existing* 2> /dev/null
file1.txt
file2.txt
file3.txt
El /dev/null
es un archivo de dispositivo especial que es como un "agujero negro":lo que envía allí simplemente desaparece.
[ Descargue esta guía para instalar aplicaciones en Linux. ]
6. Usar la redirección en un script
Imagen
=== SUMMARY OF INVESTIGATION OF chrome ===
Date/Time of the execution: 2022-03-25 18:05:50
Number of processes found.: 5
PIDs:
1245475
1249558
1316941
1382460
1384452
Este script muy simple hace lo siguiente:
- Línea 3:ejecuta un comando en el sistema operativo y lo guarda en la variable DATE_TIME.
- Línea 6:Ejecuta el
ps
comando y redirige agrep
y a un archivo.- En lugar de enviar el resultado a un archivo, podría enviarlo a una variable (como en la línea 3), pero en este caso quiero ejecutar otras acciones usando el mismo resultado, así que lo capturo. En una situación más realista, tener el archivo también podría ser útil durante el desarrollo o la resolución de problemas, por lo que puedo investigar más fácilmente lo que genera el comando.
- Línea 8:ejecuta comandos adicionales, redirige las salidas a
wc
y asigna el resultado a una variable. - Línea 9:Usa
awk
para seleccionar solo la columna 2 de la salida y ordenarla en orden descendente (solo para agregar otra tubería).
Resumir
Esos fueron algunos ejemplos de redireccionamiento de STDOUT y STDERR. Poniendo todo esto junto, te das cuenta de lo poderosa que puede ser la redirección. Al encadenar comandos individuales, manipular su salida y usar el resultado como entrada para el siguiente comando, puede realizar tareas que, de otro modo, requerirían que desarrolle un script o un programa. También podría incorporar la técnica en otros scripts, usando todo como bloques de construcción.