redirecionamento de IO com o mkpipe para fins de registro

2

Eu tenho um monte de scripts que enviam a saída para o stdout. Estou redirecionando a saída para arquivos, mas esses arquivos ficam grandes muito rapidamente. Por exemplo:

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

Gostaria de enviar a saída para um pipe nomeado. Assim, algo como o seguinte script poderia alternar o arquivo sendo gravado para:

#!/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

Poder-se-ia enviar a este script um CTRL-C (ou algum outro sinal) e efetivamente faria com que a saída do pipe começasse a gravar em um arquivo diferente (prefixado com um timestamp).

Quando executo esse script e faço eco a ele, ele começa a escrever várias linhas vazias:

   > ./redir.sh testpipe testfile &
   > echo "this is a tesT" > testpipe
   > wc -l testfile
   627915 testfile

Como posso fazer o redir.sh escrever somente em um arquivo quando o pipe que ele lê é escrito?

EDITAR

O produto final parece estar funcionando da seguinte maneira. Eu preciso testar um pouco mais para descobrir se é digno de produção

#!/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
    
por Hersheezy 10.12.2011 / 01:47

1 resposta

2

Há uma advertência sobre a leitura de um pipe nomeado. Quando você abre um pipe nomeado, a chamada open() é interrompida até que um gravador seja exibido. Quando um gravador aparecer, as chamadas read() subsequentes retornarão quaisquer dados que o gravador tenha gravado no pipe. No entanto, quando o gravador fecha o pipe (ou sai), as chamadas read() começam a retornar 0 (em vez de bloquear).

Esta é a razão pela qual, em vez de

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

alguém pode querer abrir um pipe como este

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

Desta forma, o processo não é apenas o leitor, mas também o escritor. Mesmo que você nunca realmente escreva nada para o pipe, isso garante que um gravador exista e, portanto, read() chama não retorna 0, mas bloqueia em vez de esperar que algum gravador escreva algo no pipe. / p>

Agora, quando seu script faz isso:

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

seu shell abre o pipe apenas para leitura ( O_RDONLY ).

A solução para o seu problema é fazer com que o shell abra o pipe para ler e escrever assim:

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

Observe a substituição de < $pipename por <> $pipename . Isso é o que faz com que o shell abra o pipe para leitura e gravação ( O_RDWR ).

    
por 15.12.2011 / 22:11