Bash
Redireccion
Buscar..
Sintaxis
- comando </ ruta / a / archivo # Redirigir la entrada estándar al archivo
- comando> / ruta / a / archivo # Redirecciona la salida estándar a flie
- comando file_descriptor> / ruta / a / archivo # Redirecciona la salida de file_descriptor a archivo
- comando> & file_descriptor # Redirecciona la salida a file_descriptor
- comando file_descriptor> & another_file_descriptor # Redirigir file_descriptor a another_file_descriptor
- comando <& file_descriptor # Redirigir file_descriptor a la entrada estándar
- comando &> / ruta / a / archivo # Redirigir la salida estándar y el error estándar al archivo
Parámetros
Parámetro | Detalles |
---|---|
descriptor de archivo interno | Un entero. |
dirección | Uno de > , < o <> |
descriptor de archivo externo o ruta | & seguido de un entero para el descriptor de archivo o una ruta. |
Observaciones
Los programas de la consola UNIX tienen un archivo de entrada y dos archivos de salida (las secuencias de entrada y salida, así como los dispositivos, son tratados como archivos por el sistema operativo). Estos son típicamente el teclado y la pantalla, respectivamente, pero cualquiera o todos pueden redirigirse para venir de, o ir a, un archivo u otro programa.
STDIN
es una entrada estándar, y es así como el programa recibe una entrada interactiva. STDIN
se le suele asignar el descriptor de archivo 0.
STDOUT
es una salida estándar. Todo lo que se emita en STDOUT
se considera el "resultado" del programa. STDOUT
se suele asignar el descriptor de archivo 1.
STDERR
es donde se muestran los mensajes de error. Normalmente, cuando se ejecuta un programa desde la consola, STDERR
muestra en la pantalla y no se puede distinguir de STDOUT
. STDERR
se suele asignar el descriptor de archivo 2.
El orden de redireccionamiento es importante.
command > file 2>&1
Redirige ambos ( STDOUT
y STDERR
) al archivo.
command 2>&1 > file
Los redireccionamientos que solamente STDOUT
, debido a que el descriptor de archivo 2 se redirige al archivo apuntado por el descriptor de archivo 1 (que no es el archivo file
sin embargo, cuando se evalúa la declaración).
Cada comando en una tubería tiene su propio STDERR
(y STDOUT
) porque cada uno es un proceso nuevo. Esto puede crear resultados sorprendentes si espera que una redirección afecte a toda la tubería. Por ejemplo, este comando (envuelto para legibilidad):
$ python -c 'import sys;print >> sys.stderr, "Python error!"' \
| cut -f1 2>> error.log
imprimirá "error de Python!" a la consola en lugar del archivo de registro. En su lugar, adjunte el error al comando que desea capturar:
$ python -c 'import sys;print >> sys.stderr, "Python error!"' 2>> error.log \
| cut -f1
Redireccionando salida estándar
>
redirige la salida estándar (también conocida como STDOUT
) del comando actual a un archivo u otro descriptor.
Estos ejemplos escriben la salida del comando ls
en el archivo file.txt
ls >file.txt
> file.txt ls
El archivo de destino se crea si no existe, de lo contrario, este archivo se trunca.
El descriptor de redirección predeterminado es la salida estándar o 1
cuando no se especifica ninguno. Este comando es equivalente a los ejemplos anteriores con la salida estándar indicada explícitamente:
ls 1>file.txt
Nota: la redirección es inicializada por el shell ejecutado y no por el comando ejecutado, por lo tanto, se realiza antes de la ejecución del comando.
Redireccionando STDIN
<
lee de su argumento derecho y escribe en su argumento izquierdo.
Para escribir un archivo en STDIN
debemos leer /tmp/a_file
y escribir en STDIN
es decir, 0</tmp/a_file
Nota: el descriptor de archivo interno está predeterminado en 0
( STDIN
) para <
$ echo "b" > /tmp/list.txt
$ echo "a" >> /tmp/list.txt
$ echo "c" >> /tmp/list.txt
$ sort < /tmp/list.txt
a
b
c
Redireccionando tanto STDOUT como STDERR
Los descriptores de archivos como 0
y 1
son punteros. Cambiamos lo que apuntan los descriptores de archivos con la redirección. >/dev/null
significa 1
puntos a /dev/null
.
Primero, STDERR
1
( STDOUT
) a /dev/null
luego STDERR
2
( STDERR
) a lo que apunta 1
.
# STDERR is redirect to STDOUT: redirected to /dev/null,
# effectually redirecting both STDERR and STDOUT to /dev/null
echo 'hello' > /dev/null 2>&1
Esto puede reducirse aún más a lo siguiente:
echo 'hello' &> /dev/null
Sin embargo, esta forma puede ser indeseable en la producción si la compatibilidad del shell es una preocupación, ya que entra en conflicto con POSIX, introduce ambigüedad en el análisis y los shells sin esta característica lo malinterpretarán:
# Actual code
echo 'hello' &> /dev/null
echo 'hello' &> /dev/null 'goodbye'
# Desired behavior
echo 'hello' > /dev/null 2>&1
echo 'hello' 'goodbye' > /dev/null 2>&1
# Actual behavior
echo 'hello' &
echo 'hello' & goodbye > /dev/null
NOTA: &>
se sabe que funciona como se desea tanto en Bash como en Zsh.
Redireccionando STDERR
2
es STDERR
.
$ echo_to_stderr 2>/dev/null # echos nothing
Definiciones:
echo_to_stderr
es un comando que escribe "stderr"
en STDERR
echo_to_stderr () {
echo stderr >&2
}
$ echo_to_stderr
stderr
Anexar vs Truncar
Truncar >
- Crear archivo especificado si no existe.
- Truncar (eliminar el contenido del archivo)
- Escribir en el archivo
$ echo "first line" > /tmp/lines
$ echo "second line" > /tmp/lines
$ cat /tmp/lines
second line
Añadir >>
- Crear archivo especificado si no existe.
- Adjuntar archivo (escritura al final del archivo).
# Overwrite existing file
$ echo "first line" > /tmp/lines
# Append a second line
$ echo "second line" >> /tmp/lines
$ cat /tmp/lines
first line
second line
STDIN, STDOUT y STDERR explicados
Los comandos tienen una entrada (STDIN) y dos tipos de salidas, salida estándar (STDOUT) y error estándar (STDERR).
Por ejemplo:
STDIN
root@server~# read
Type some text here
La entrada estándar se utiliza para proporcionar entrada a un programa. (Aquí estamos usando la read
orden interna para leer una línea de STDIN.)
Repartir
root@server~# ls file
file
La salida estándar se usa generalmente para la salida "normal" de un comando. Por ejemplo, ls
lista los archivos, por lo que los archivos se envían a STDOUT.
STDERR
root@server~# ls anotherfile
ls: cannot access 'anotherfile': No such file or directory
El error estándar se usa (como su nombre lo indica) para los mensajes de error. Como este mensaje no es una lista de archivos, se envía a STDERR.
STDIN, STDOUT y STDERR son los tres flujos estándar. Se identifican en el shell por un número en lugar de un nombre:
0 = Estándar en
1 = salida estándar
2 = error estándar
De forma predeterminada, STDIN está conectado al teclado, y tanto STDOUT como STDERR aparecen en el terminal. Sin embargo, podemos redirigir STDOUT o STDERR a lo que necesitemos. Por ejemplo, supongamos que solo necesita la salida estándar y todos los mensajes de error impresos en el error estándar deben suprimirse. Ahí es cuando utilizamos los descriptores 1
y 2
.
Redireccionando STDERR a / dev / null
Tomando el ejemplo anterior,
root@server~# ls anotherfile 2>/dev/null
root@server~#
En este caso, si hay algún STDERR, se redirigirá a / dev / null (un archivo especial que ignora cualquier cosa que se coloque en él), por lo que no obtendrá ninguna salida de error en el shell.
Redirigiendo múltiples comandos al mismo archivo
{
echo "contents of home directory"
ls ~
} > output.txt
Utilizando tuberías con nombre
A veces es posible que desee generar algo por un programa e ingresarlo en otro programa, pero no puede usar una canalización estándar.
ls -l | grep ".log"
Usted podría simplemente escribir en un archivo temporal:
touch tempFile.txt
ls -l > tempFile.txt
grep ".log" < tempFile.txt
Esto funciona bien para la mayoría de las aplicaciones, sin embargo, nadie sabrá qué hace tempFile
y alguien podría eliminarlo si contiene la salida de ls -l
en ese directorio. Aquí es donde una tubería con nombre entra en juego:
mkfifo myPipe
ls -l > myPipe
grep ".log" < myPipe
myPipe
es técnicamente un archivo (todo está en Linux), así que hagamos ls -l
en un directorio vacío en el que acabamos de crear una tubería:
mkdir pipeFolder
cd pipeFolder
mkfifo myPipe
ls -l
La salida es:
prw-r--r-- 1 root root 0 Jul 25 11:20 myPipe
Observe el primer carácter de los permisos, aparece como una canalización, no como un archivo.
Ahora hagamos algo genial.
Abra un terminal y tome nota del directorio (o cree uno para que la limpieza sea fácil) y haga una tubería.
mkfifo myPipe
Ahora vamos a poner algo en la tubería.
echo "Hello from the other side" > myPipe
Notará que esto cuelga, el otro lado de la tubería todavía está cerrado. Abramos el otro lado de la tubería y dejemos pasar esas cosas.
Abra otro terminal y vaya al directorio en el que se encuentra la tubería (o si lo sabe, prepárelo en la tubería):
cat < myPipe
Notará que después hello from the other side
salir el hello from the other side
, el programa en el primer terminal termina, al igual que en el segundo terminal.
Ahora ejecuta los comandos a la inversa. Comience con cat < myPipe
y luego cat < myPipe
eco de algo en él. Todavía funciona, porque un programa esperará hasta que algo se coloque en la tubería antes de terminar, porque sabe que tiene que obtener algo.
Las tuberías con nombre pueden ser útiles para mover información entre terminales o entre programas.
Las tuberías son pequeñas. Una vez lleno, el escritor bloquea hasta que algún lector lee el contenido, por lo que necesita ejecutar el lector y el escritor en diferentes terminales o ejecutar uno u otro en segundo plano:
ls -l /tmp > myPipe &
cat < myPipe
Más ejemplos usando tuberías con nombre:
Ejemplo 1 - todos los comandos en el mismo terminal / mismo shell
$ { ls -l && cat file3; } >mypipe & $ cat <mypipe # Output: Prints ls -l data and then prints file3 contents on screen
Ejemplo 2 - todos los comandos en el mismo terminal / mismo shell
$ ls -l >mypipe & $ cat file3 >mypipe & $ cat <mypipe #Output: This prints on screen the contents of mypipe.
file3
se muestran los primeros contenidos defile3
y luego se muestran los datos dels -l
(configuración LIFO).Ejemplo 3 - todos los comandos en el mismo terminal / mismo shell
$ { pipedata=$(<mypipe) && echo "$pipedata"; } & $ ls >mypipe # Output: Prints the output of ls directly on screen
$pipedata
cuenta que la variable$pipedata
no está disponible para su uso en el terminal principal / shell principal, ya que el uso de&
invoca una subshell y$pipedata
solo estaba disponible en esta subshell.Ejemplo 4 - todos los comandos en el mismo terminal / mismo shell
$ export pipedata $ pipedata=$(<mypipe) & $ ls -l *.sh >mypipe $ echo "$pipedata" #Output : Prints correctly the contents of mypipe
Esto imprime correctamente el valor de la variable
$pipedata
en el shell principal debido a la declaración de exportación de la variable. El terminal principal / shell principal no se bloquea debido a la invocación de un shell de fondo (&
).
Imprimir mensajes de error a stderr
Los mensajes de error generalmente se incluyen en un script para fines de depuración o para proporcionar una experiencia de usuario enriquecida. Simplemente escribiendo un mensaje de error como este:
cmd || echo 'cmd failed'
Puede funcionar para casos simples pero no es la forma habitual. En este ejemplo, el mensaje de error contaminará la salida real de la secuencia de comandos al mezclar los errores y la salida exitosa en la salida stdout
.
En resumen, el mensaje de error debe ir a stderr
no a stdout
. Es bastante simple:
cmd || echo 'cmd failed' >/dev/stderr
Otro ejemplo:
if cmd; then
echo 'success'
else
echo 'cmd failed' >/dev/stderr
fi
En el ejemplo anterior, el mensaje de éxito se imprimirá en la stdout
mientras que el mensaje de error se imprimirá en stderr
.
Una mejor manera de imprimir un mensaje de error es definir una función:
err(){
echo "E: $*" >>/dev/stderr
}
Ahora, cuando tienes que imprimir un error:
err "My error message"
Redireccionamiento a direcciones de red
Bash trata algunas rutas como especiales y puede hacer algunas comunicaciones de red escribiendo a /dev/{udp|tcp}/host/port
. Bash no puede configurar un servidor de escucha, pero puede iniciar una conexión, y para TCP puede leer al menos los resultados.
Por ejemplo, para enviar una solicitud web simple uno podría hacer:
exec 3</dev/tcp/www.google.com/80
printf 'GET / HTTP/1.0\r\n\r\n' >&3
cat <&3
y los resultados de la página web predeterminada de www.google.com
se imprimirán a la stdout
estándar.
similar
printf 'HI\n' >/dev/udp/192.168.1.1/6666
enviaría un mensaje UDP que contenga HI\n
a un oyente en 192.168.1.1:6666