¿3> & 1 implica 4> & 3 5> & 3 etc.?

31

Yo esperaría

echo foo | tee /proc/self/fd/{3..6} 3>&1

fallar con errores como / proc / self / fd / 4: No existe tal archivo o directorio , etc., pero para mi sorpresa, genera

foo
foo
foo
foo
foo

Es como si 3>&1todos los descriptores siguientes fueran redirigidos a stdout, excepto que no funciona si cambio 3a otra cosa, como

$ echo foo | tee /proc/self/fd/{3..6} 4>&1
tee: /proc/self/fd/3: No such file or directory
tee: /proc/self/fd/5: No such file or directory
tee: /proc/self/fd/6: No such file or directory
foo
foo
$ echo foo | tee /proc/self/fd/{4..6} 4>&1
tee: /proc/self/fd/5: No such file or directory
tee: /proc/self/fd/6: No such file or directory
foo
foo

¿Hay alguna explicación para este comportamiento?

oguz ismail
fuente

Respuestas:

31

strace muestra esta secuencia de llamadas al sistema:

$ strace -o strace.log tee /proc/self/fd/{3..6} 3>&1
...
$ cat strace.log
...
openat(AT_FDCWD, "/proc/self/fd/3", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 4
openat(AT_FDCWD, "/proc/self/fd/4", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 5
openat(AT_FDCWD, "/proc/self/fd/5", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 6
openat(AT_FDCWD, "/proc/self/fd/6", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 7
...

La primera línea se abre /proc/self/fd/3y le asigna el siguiente número fd disponible, 4. /proc/self/fd/3es una ruta especial. Abrirlo tiene un efecto similar a duplicar fd 3: fd 4 apunta al mismo lugar que fd 3, el tty.

Lo mismo sucede para cada openat()llamada sucesiva . Cuando el polvo se asienta fds 4, 5, 6 y 7 son todos duplicados de fd 3.

  • 1 → tty
  • 3 → tty
  • 4 → tty
  • 5 → tty
  • 6 → tty
  • 7 → tty

Tenga en cuenta que la 3>&1redirección no es importante. Lo importante es que estamos pidiendo tee para abrir /proc/self/fd/Ndonde N ya está en uso. Deberíamos obtener el mismo resultado si nos deshacemos 3>&1y comenzamos el tee en su /proc/self/fd/2lugar. Veamos:

$ echo foo | tee /proc/self/fd/{2..6}
foo
foo
foo
foo
foo
foo

¡Confirmado! Mismo resultado.

También podemos repetir el mismo número fd una y otra vez. Obtenemos el mismo resultado cuando presionamos fd 6. Para cuando llega al último, ha abierto suficientes descriptores para hacer posible el salto a 6.

$ echo foo | tee /proc/self/fd/{2,2,2,2,6}
foo
foo
foo
foo
foo
foo
John Kugelman
fuente