Quiero canalizar dos programas en uno. Si mi shell lo admite, puedo usarSustitución de procesos. Por ejemplo, para enumerar las líneas comunes de dos archivos en orden indiferente, puedo usar
comm -12 <(sort a) <(sort b)
Sin embargo, la sustitución de procesos no existe en términos simples sh
. Puedo hacerlo con portabilidad POSIX completa creando untubería con nombre, pero esto es engorroso ya que requiere encontrar un directorio para FIFO y limpiarlo después. Un buen compromiso práctico es usar dos construcciones de tubería de shell y usar la mezcla de descriptores de archivos para mover una tubería a otro descriptor de archivo, luego usarla /dev/fd
para designar la tubería, lo que funciona en la mayoría de las variantes de Unix:
sort a | { exec 3<&0; sort b | comm -12 /dev/fd/0 /dev/fd/3; }
Esto funciona en dash, bash, BusyBox sh, etc. pero no en ksh93 y mksh. ¿Por qué?
$ mksh -c 'sort a | { exec 3<&0; sort b | comm -12 /dev/fd/0 /dev/fd/3; }'
$ ksh93 -c 'sort a | { exec 3<&0; sort b | comm -12 /dev/fd/0 /dev/fd/3; }'
comm: /dev/fd/0: No such device or address
Respuesta1
A diferencia de las redirecciones de otros comandos, las redirecciones exec
integradas pueden cerrarse cuando el shell ejecuta un programa externo.POSIX permite ambos comportamientos. Ksh (tanto ATT ksh como pdksh y mksh) cierran estos descriptores cuando ejecutan una utilidad externa (es decir, para una redirección en el exec
sistema incorporado, después de llamar dup2
para realizar la redirección, configuran la FD_CLOEXEC
bandera en el nuevo descriptor). Bourne shell, dash, bash, zsh y BusyBox sh tratan esta redirección como cualquier otra redirección.
Una solución más portátil al problema de los dos canales de entrada (suponiendo la existencia de /dev/fd
) es realizar otra redirección en el comando que lee la entrada, moviendo el descriptor del archivo a uno nuevo. Esta redirección adicional no establece el indicador de cierre al ejecutar en el nuevo descriptor.
sort a | { exec 3<&0; sort b | comm -12 /dev/fd/0 /dev/fd/4 4<&3; }
Esto funciona en pdksh/mksh y en ksh93r, pero no en versiones recientes de ksh (93s+ 2008-01-31 o 93u+ 2012-08-01). No entiendo qué está haciendo ksh allí.