Algunas conchas, como bash
, admite Sustitución de procesos, que es una forma de presentar la salida del proceso como un archivo, como este:
$ diff <(sort file1) <(sort file2)
Sin embargo, esta construcción no es POSIX y, por lo tanto, no es portátil. ¿Cómo se puede lograr la sustitución de procesos de una manera compatible con POSIX? (es decir, uno que funciona en /bin/sh
) ?
nota:la pregunta no es cómo diferenciar dos archivos ordenados, ¡ese es solo un ejemplo artificial para demostrar la sustitución del proceso!
Respuesta aceptada:
Esa característica fue introducida por ksh
(documentado por primera vez en ksh86) y estaba haciendo uso de /dev/fd/n
función
(agregada de forma independiente en algunos sistemas BSD y AT&T anteriormente).
En ksh
y hasta ksh93u, no funcionaría a menos que su sistema fuera compatible con /dev/fd/n
. zsh, bash y ksh93u+
y superiores pueden hacer uso de canalizaciones temporales con nombre (canalizaciones con nombre agregadas en System III) donde /dev/fd/n
no están disponibles.
En sistemas donde /dev/fd/n
está disponible (POSIX no los especifica),
puede realizar la sustitución del proceso (p. ej., diff <(cmd1) <(cmd2)
) usted mismo con:
{
cmd1 4<&- | {
# in here fd 3 points to the reading end of the pipe
# from cmd1, while fd 0 has been restored from the original
# stdin (saved on fd 4, now closed as no longer needed)
cmd2 3<&- | diff /dev/fd/3 -
} 3<&0 <&4 4<&- # restore the original stdin for cmd2
} 4<&0 # save a copy of stdin for cmd2
Sin embargo, eso no funciona con ksh93
en Linux como allí, las tuberías de shell se implementan con pares de sockets en lugar de tuberías y abriendo /dev/fd/3
donde fd 3 apunta a un socket no funciona en Linux.
Aunque POSIX no especifica /dev/fd/n
, especifica canalizaciones con nombre. Las canalizaciones con nombre funcionan como canalizaciones normales, excepto que puede acceder a ellas desde el sistema de archivos. El problema aquí es que debe crear temporales y limpiarlos después, lo cual es difícil de hacer de manera confiable, especialmente considerando que POSIX no tiene un mecanismo estándar (como un mktemp -d
como se encuentra en algunos sistemas) para crear archivos o directorios temporales, y el manejo de señales (para limpiar al colgar o eliminar) también es difícil de hacer de forma portátil.
Podrías hacer algo como:
tmpfifo() (
n=0
until
fifo=$1.$$.$n
mkfifo -m 600 -- "$fifo" 2> /dev/null
do
n=$((n + 1))
# give up after 20 attempts as it could be a permanent condition
# that prevents us from creating fifos. You'd need to raise that
# limit if you intend to create (and use at the same time)
# more than 20 fifos in your script
[ "$n" -lt 20 ] || exit 1
done
printf '%s\n' "$fifo"
)
cleanup() { rm -f -- "$fifo"; }
fifo=$(tmpfifo /tmp/fifo) || exit
cmd2 > "$fifo" & cmd1 | diff - "$fifo"
cleanup
(sin ocuparse del manejo de la señal aquí).
Relacionado:¿El proceso se completó inmediatamente después de abrir la Terminal y es imposible agregar comandos?