2

У меня есть куча скриптов, которые отправляют вывод на стандартный вывод. Я перенаправляю вывод в файлы, но эти файлы становятся очень большими очень быстро. Например:

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

Я хотел бы вместо этого отправить вывод в именованный канал, чтобы что-то вроде следующего скрипта могло переключить записываемый файл:

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

Можно послать этот сценарий CTRL-C (или какой-то другой сигнал), и он фактически заставит вывод канала начать запись в другой файл (с добавлением временной метки).

Когда я запускаю этот скрипт, а затем что-то передаю ему, он начинает писать тонну пустых строк:

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

Как я могу заставить redir.sh записывать в файл только тогда, когда записывается канал, из которого он читает?

РЕДАКТИРОВАТЬ

Конечный продукт, кажется, работает следующим образом. Мне нужно проверить еще немного, чтобы выяснить, является ли это достойным производства

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

1 ответ1

2

Существует предостережение относительно чтения из именованного канала. Когда вы открываете именованный канал, ваш вызов open() зависает, пока не появится писатель. Когда писатель обнаруживается, последующие вызовы read() вернут все данные, которые писатель записал в канал. Однако, когда средство записи закрывает канал (или выходит ), вызовы read() начинают возвращать 0 (а не блокировать).

Это причина того, что вместо

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

кто-то может захотеть открыть такую трубу

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

Таким образом, процесс не только читатель, но и писатель. Несмотря на то, что вы никогда ничего не пишете в канал, это гарантирует, что писатель существует, и, следовательно, вызовы read() не возвращают 0, а вместо этого блокируют ожидание того, что какой-нибудь писатель что-то записывает в канал.

Теперь, когда ваш скрипт делает это:

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

ваша оболочка открывает канал только для чтения (O_RDONLY).

Решение вашей проблемы - сделать так, чтобы shell открывал канал для чтения и записи следующим образом:

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

Обратите внимание на замену < $pipename на <> $pipename . Это то, что заставляет оболочку открывать канал для чтения и записи (O_RDWR).

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .