alquitrán a tubería pero mantenga la salida detallada -v separada de STDERR

12

Un comando tar normal

tar cvf foo.tar ./foo >foo.out 2>foo.err

tiene tres flujos de salida de E / S

  • archivar datos en foo.tar
  • lista de nombres de archivo a STDOUT (redirigido a foo.out)
  • mensajes de error a STDERR (redirigido a foo.err)

Luego puedo inspeccionar foo.err en busca de mensajes de error sin tener que leer la lista de nombres de archivo.

si quiero hacer algo con los datos del archivo (canalizarlos a través de netcat o un programa de compresión especial), puedo usar la -f -opción tar

tar cvf - ./foo 2>foo.err | squish > foo.tar.S

Pero ahora mi lista de nombres de archivo se mezcla con mis mensajes de error porque la -vsalida de tar obviamente no puede ir a STDOUT (ahí es donde fluyen los datos del archivo), por lo que tar escribe ingeniosamente en STDERR.

Usando el shell Korn, ¿hay alguna manera de construir un comando que canalice la secuencia de archivo a otro comando pero aún así capture la -vsalida por separado de cualquier mensaje de error.

RedGrittyBrick
fuente
¿Estás familiarizado con tee? Esto parece un caso de uso bastante válido para ello.
HalosGhost

Respuestas:

9

Si su sistema admite /dev/fd/n:

tar cvf /dev/fd/3 ./foo 3>&1 > foo.out 2>foo.err | squish > foo.tar.S

Que con las implementaciones de AT&T de ksh( bashoo zsh) podría escribir usando la sustitución de procesos :

tar cvf >(squish > foo.tar.S) ./foo > foo.out 2>foo.err

Eso está haciendo exactamente lo mismo, excepto que esta vez, el shell decide qué descriptor de archivo usar en lugar de 3(generalmente por encima de 9). Otra diferencia es que esta vez, obtienes el estado de salida de en tarlugar de squish. En los sistemas que no son compatibles /dev/fd/n, algunos shells pueden recurrir a canalizaciones con nombre para esa característica.

Si su sistema no es compatible /dev/fd/no su shell no puede hacer uso de canalizaciones con nombre para su sustitución de procesos, ahí es donde tendrá que lidiar con las canalizaciones con nombre a mano .

Stéphane Chazelas
fuente
6

Tienes que usar una tubería con nombre para eso.

Primero cree uno en la carpeta:

mkfifo foo.pipe

Luego usa ese comando:

tar cvf foo.pipe ./foo >foo.out 2>foo.err & cat foo.pipe >foo.tar

Aviso: la parte cat, ahora también puede ser gzipo lo que sea, que se puede leer desde una tubería:

tar cvf foo.pipe ./foo >foo.out 2>foo.err & gzip -c foo.pipe >foo.tar

Explicación:

La salida se escribe en el tubo de nombre ( foo.pipe), donde otro proccess ( cat, gzip, netcat) lee de. Por lo tanto, no pierde los canales stdout / stderr para obtener información.

caos
fuente
1
Podría valer la pena señalar las implicaciones de usar tuberías con nombre . 1) lo mejor es establecer un umask 077(o usar un directorio temporal privado) para evitar que otros procesos lean o escriban en él (en muchos sistemas, las canalizaciones con nombre, como otros archivos se crean de forma legible por mundo), 2) necesita asegurarse el conducto con nombre solo lo usa cada instancia de su script (de nuevo, un directorio temporal privado único ayuda) 3) Eso significa que necesita limpiar después o si se interrumpe.
Stéphane Chazelas
1
+1 - Me gusta esta respuesta. Desafortunadamente para mí, hay algo extraño en las tuberías con nombre en mi (antiguo) sistema que las hace poco confiables cuando intento esto.
RedGrittyBrick
1
@ StéphaneChazelas - Creo que a veces puede ser más fácil limpiar primero, como:p="/tmp/pipe$$"; mkfifo "$p"; (read na; cmd[s]...) <>"$p" & (echo;rm "$p"; cmd[s]...) >"$p"
mikeserv