¿Puedo duplicar la salida de una tubería?

¿Puedo duplicar la salida de una tubería?

Bueno, la tarea es simple: una parte de mi script tiene que calcular hashes md5 y sha1. La entrada es un archivo (un archivo grande) y los hashes deben colocarse en las variables MD y SH para su posterior composición de salida.

Si bien los archivos procesados ​​son realmente grandes (cientos de GB), intento utilizar algún tipo de uso múltiple de los datos una vez leídos. Encontré algo llamado sustitución de procesos que adopté de la siguiente manera:

$ dd if=big.tgz 2>/dev/null |tee >(sha1sum ) > >(md5sum ) ;

en lugar de:

$ SH=$(sha1sum big.tgz); MD=$(md5sum big.tgz);

Pero encontré lo siguiente:

  • aparentemente no hay ahorro de recursos ni de tiempo ya que ambos llevan aprox. 40s (para archivos de 4,776 GB)

  • No tengo idea de cómo guardar el resultado del subproceso >(md5sum )en la variable MD para usarlo más adelante en el script.

Intenté entender el pipexec pero ni siquiera las bonitas ilustraciones en color tuvieron éxito hasta el momento.

¿Existe alguna otra forma de redirigir la salida a una variable, además de VAR=$(command)?

Respuesta1

En cuanto al rendimiento, es posible que esté limitado por la CPU. En realidad, 4,7 TB en 40 segundos tanto para MD5 como para sha1sum parecen rápidos. Incluso si trabajas de esta manera. Por si sirve de algo, habrá reducido la E/S del disco.

Realmente no es necesario ddpara esto. También puede simplemente escribir la salida de sha1sum y md5sum directamente en un archivo para su uso posterior.

tee < big.tgz  >(sha1sum > big.tgz.sha1 ) > >(md5sum > big.tgz.md5 )
sha1=`cat big.tgz.sha1`
md5=`cat big.tgz.md5`

Sugiero usar archivos temporales como este ( big.tgz.sha1y big.tgz.md5) porque AFAIK no hay forma de configurar simultáneamente dos variables con valores diferentes. Puede capturar uno directamente en una variable, pero no ambos. Y permitir que ambos md5sumescriban sha1sumen la misma salida estándar al mismo tiempo podría causar problemas impredecibles.

Respuesta2

Bueno, puedes agregar otra redirección dentro:

tee < big.tgz >(sha1sum > big.tgz.sha1sum) >(md5sum > big.tgz.md5sum)

También puede tomar el resultado tal como está, considerando que es fácil diferenciar entre sha1 y md5 (longitud diferente para que no haya confusión sobre cuál es cuál).

También hay utilidades que calculan múltiples sumas de verificación por sí solas, sin pasar por obstáculos tee.

En realidad, lo anterior también se puede escribir sin tee:

sha1sum big.tgz > big.tgz.sha1sum &
md5sum big.tgz > big.tgz.md5sum
wait # for sha1sum

En teoría, esto es malo ya que los datos se leen del disco dos veces.

En la práctica, ejecutar ambos lectores en paralelo (y en segundo plano) debería permitir que la caché del disco lo maneje de modo que los datos se lean efectivamente solo una vez. Esto supone que el cálculo hash es rápido y la E/S es lenta, por lo que ningún proceso puede escapar del otro.

(Anteriormente publiqué sobre leer dos veces en otro contexto aquí:Usando pv con md5sum- Aunque normalmente funciona, conlleva algunos riesgos, por lo que teesigue siendo el método más fiable. )

Respuesta3

parsetde GNU Parallel está diseñado para configurar variables en paralelo y --teeconectará la entrada a múltiples comandos:

parset md5,sha1,sha256 --pipe --tee {} ::: md5sum sha1sum sha256sum < bigfile
echo $sha1

parset sumarr --pipe --tee {} ::: md5sum sha1sum sha256sum < bigfile
echo ${sumarr[1]}

información relacionada