Es una vieja pregunta pero una cosa necesita aclaración.
Si bien las respuestas de Carl Norum y dogbane son correctas, la suposición es cambiar la secuencia de comandos para que funcione.
Lo que me gustaría señalar es que que no es necesario cambiar el guión:
#!/bin/bash
echo "This"
echo "is" >&2
echo "a" >&3
echo "test." >&4
Funciona si se invoca de forma diferente:
./fdtest 3>&1 4>&1
lo que significa para redirigir los descriptores de archivos 3 y 4 a 1 (que es salida estándar).
El punto es que el guión está perfectamente bien en su deseo de escribir en los descriptores que no sean sólo 1 y 2 (stdout y stderr) si esos descriptores son proporcionados por el proceso padre.
Su ejemplo es en realidad bastante interesante porque este script puede escribir en 4 archivos diferentes:
./fdtest >file1.txt 2>file2.txt 3>file3.txt 4>file4.txt
Ahora usted tiene la salida en 4 archivos separados:
$ for f in file*; do echo $f:; cat $f; done
file1.txt:
This
file2.txt:
is
file3.txt:
a
file4.txt:
test.
¿Cuál es más interesante sobre esto es que su programa no tiene que tener permisos de escritura para esos archivos, porque en realidad no los abre.
Por ejemplo, cuando corro sudo -s
para cambiar al usuario root, cree un directorio como raíz, y tratar de ejecutar el siguiente comando como mi usuario normal (RSP en mi caso) así:
# su rsp -c '../fdtest >file1.txt 2>file2.txt 3>file3.txt 4>file4.txt'
me aparece un error:
bash: file1.txt: Permission denied
Pero si hago el cambio de dirección fuera del su
:
# su rsp -c '../fdtest' >file1.txt 2>file2.txt 3>file3.txt 4>file4.txt
(nótese la diferencia entre comillas simples) funciona y consigo:
# ls -alp
total 56
drwxr-xr-x 2 root root 4096 Jun 23 15:05 ./
drwxrwxr-x 3 rsp rsp 4096 Jun 23 15:01 ../
-rw-r--r-- 1 root root 5 Jun 23 15:05 file1.txt
-rw-r--r-- 1 root root 39 Jun 23 15:05 file2.txt
-rw-r--r-- 1 root root 2 Jun 23 15:05 file3.txt
-rw-r--r-- 1 root root 6 Jun 23 15:05 file4.txt
cuales son 4 ficheros titularidad de la raíz en un directorio propiedad de la raíz - a pesar de que el guión no tenía permisos para crear esos archivos.
Otro ejemplo sería usar chroot jail o un contenedor y ejecutar un programa dentro del cual no tendría acceso a esos archivos, incluso si se ejecutara como root y aún redirigiera esos descriptores externamente donde lo necesita, sin dar realmente acceso a todo el sistema de archivos o cualquier otra cosa a este script.
El punto es que ha descubierto un mecanismo muy interesante y útil. No tiene que abrir todos los archivos dentro de su script como se sugirió en otras respuestas. Algunas veces es útil redirigirlos durante la invocación del script.
para resumir, esto:
echo "This"
es en realidad equivalente a:
echo "This" >&1
y ejecutar el programa como:
./program >file.txt
es lo mismo que:
./program 1>file.txt
El número 1 es simplemente un número predeterminado y es stdout.
Pero incluso este programa:
#!/bin/bash
echo "This"
puede producir un error de "Bad descriptor". ¿Cómo? Cuando se realiza según:
./fdtest2 >&-
La salida será:
./fdtest2: line 2: echo: write error: Bad file descriptor
Adición de >&-
(que es el mismo que 1>&-
) significa el cierre de la salida estándar. Agregar 2>&-
significaría cerrar el stderr.
Incluso puede hacer una cosa más complicada.Su guión original:
#!/bin/bash
echo "This"
echo "is" >&2
echo "a" >&3
echo "test." >&4
cuando se ejecuta con sólo:
./fdtest
impresiones:
This
is
./fdtest: line 4: 3: Bad file descriptor
./fdtest: line 5: 4: Bad file descriptor
pero se puede hacer descriptores 3 y 4 de trabajo, pero el número 1 fallar ejecutando:
./fdtest 3>&1 4>&1 1>&-
Emite:
./fdtest: line 2: echo: write error: Bad file descriptor
is
a
test.
Si quieren tanto descriptores 1 y 2 fallan, se ejecutan de esta manera:
./fdtest 3>&1 4>&1 1>&- 2>&-
que se obtiene:
a
test.
¿Por qué? ¿No falló nada? Lo hizo pero sin stderr (número de descriptor de archivo 2) ¡no vio los mensajes de error!
Creo que es muy útil experimentar de esta manera para tener una idea de cómo funcionan los descriptores y su redirección.
Su secuencia de comandos es un ejemplo muy interesante de hecho, y yo argumento que no está roto en absoluto, ¡solo lo estaba usando incorrectamente! :)
¡Eso es lo que estoy buscando! Entonces, ¿debo especificar un archivo para que lo use como un lugar de almacenamiento temporal con el comando exec, y luego cerrarlo cuando haya terminado? Lo siento, estoy un poco confuso con el comando ejecutivo, no lo uso mucho. – Trcx
sí, pero no es temporal. El archivo existirá incluso después de que se complete su programa. – dogbane
Eso podría funcionar bien, estoy intentando portar algunas secuencias de comandos para que sean compatibles con el programador de tareas crontab, pero estoy teniendo problemas ya que cron no permite la conexión de stdout en las secuencias de comandos. – Trcx