Redirección de E / S con mkpipe para fines de registro

2

Tengo un montón de scripts que envían resultados a stdout. Estoy redirigiendo la salida a archivos, pero estos archivos se agrandan muy rápidamente. Por ejemplo:

./script_with_lots_of_outpu.sh 2>&1 mylog.txt &

En su lugar, me gustaría enviar la salida a una tubería con nombre para que algo como el siguiente script pueda cambiar el archivo en el que se escribe:

#!/bin/bash
if [ $# -ne 2 ]; then
echo "USAGE: ./redir.sh pipename filename" 
fi

pipename=$1
filename=$2
trap filename="`date +%s`$filename" 2
mkfifo $pipename

while [ 1 -eq 1 ]
do
    read input
    echo $input >> $filename
done < $pipename

Uno podría enviar a este script un CTRL-C (o alguna otra señal) y efectivamente provocaría que la salida de la tubería comience a escribir en un archivo diferente (antepuesto con una marca de tiempo).

Cuando ejecuto este script y luego le hago eco, comienza a escribir un montón de líneas vacías:

   > ./redir.sh testpipe testfile &
   > echo "esto es un tesT"> testpipe
   > wc -l archivo de prueba
   627915 archivo de prueba

¿Cómo puedo hacer que redir.sh solo escriba en un archivo cuando la tubería de la que lee está escrita?

EDITAR

El producto final parece estar funcionando de la siguiente manera. Necesito probar un poco más para averiguar si es digno de producción

#!/bin/bash

if [ $# -ne 2 ]; then
    echo "USAGE: ./redir.sh pipename filename" 
    exit -1
fi

pipename=$1; rm $pipename;
origname=$2.log
filename=$2

rename()
{
    filename="$origname-`date +%s`"
    mv $origname $filename
    nohup nice -n 20 tar -czvf $filename.tar.gz $filename &
    trap rename 2
}

mkfifo $pipename
trap rename 2

while [ 1 -eq 1 ]
do
    read input
    echo $input >> $origname
done <> $pipename
Hersheezy
fuente

Respuestas:

2

Hay una advertencia sobre la lectura de una tubería con nombre. Cuando abre una tubería con nombre, su open()llamada se cuelga hasta que aparece un escritor. Cuando aparece un escritor, las read()llamadas posteriores devolverán los datos que el escritor haya escrito en la tubería. Sin embargo, cuando el escritor cierra la tubería (o sale), las read()llamadas comienzan a devolver 0 (en lugar de bloquear).

Esta es la razón por la que en lugar de

int fd = open("testpipe", O_RDONLY);

uno podría querer abrir una tubería como esta

int fd = open("testpipe", O_RDWR);

De esta manera, el proceso no es solo el lector, sino también el escritor. Aunque en realidad nunca escribe nada en la tubería, esto garantiza que exista un escritor y, por read()lo tanto, las llamadas no devuelven 0, sino que bloquean, en cambio, esperan que algún escritor escriba algo en la tubería.

Ahora, cuando tu script hace esto:

while [ 1 -eq 1 ]
do
    read input
    ...
done < $pipename

su caparazón abre la tubería para solo lectura ( O_RDONLY).

La solución a su problema es hacer que Shell abra la tubería para leer y escribir así:

while [ 1 -eq 1 ]
do
    read input
    ...
done <> $pipename

Tenga en cuenta el reemplazo de < $pipenamecon <> $pipename. Esto es lo que hace que el shell abra la tubería para leer y escribir ( O_RDWR).

Adam Zalcman
fuente
1
increíblemente lamento por haber tardado tanto en responder. Su sugerencia funcionó muy bien.
Hersheezy