Перенаправление ввода / вывода с помощью mkpipe для целей регистрации

3823
Hersheezy

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

./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 & > эхо "это тест"> тестпайп > wc -l testfile 627915 тестовый файл 

Как я могу заставить 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 
2

1 ответ на вопрос

2
Adam Zalcman

Существует предостережение относительно чтения из именованного канала. Когда вы открываете именованный канал, ваш 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).

невероятно жаль, что так долго отвечал. Ваше предложение сработало прекрасно. Hersheezy 12 лет назад 0

Похожие вопросы