Неблокирующая буферизованная именованная труба?

20

Я ищу то, что, как я подозреваю, не существует: неблокируемый буферизованный именованный канал (fifo) для использования из командной строки. Что-то подобное существует?

Вот пример использования: Предположим, у меня есть процесс, который будет долго работать в фоновом режиме и израсходовать много выходных данных stdout. Меня не очень волнует вывод, и я не хочу его хранить (возможно, мне не хватает места), но я хотел бы периодически «заходить» и следить за тем, что он делает, а затем снова выбрасывать и оставь это делать свою работу. Поэтому я бы хотел перенаправить вывод в этот теоретически буферизованный неблокирующий именованный канал, а затем периодически подключаться к нему.

В общем, я хочу начать так ( 10Mразмер буфера):

mkmagicfifo magicfifo 10M
spewingprocess > magicfifo &

... и периодически заглядывать, чтобы посмотреть, что происходит ...

tail -f magicfifo

... без magicfifo сохранения всего вывода (то есть, не обычного файла) и без него, блокирующего процесс выброса, когда он заполняется и не изменяется (так что не совсем обычный именованный канал).

Я не думаю, что решения, включающие tailили pruneбудут делать это (ну, я могу придумать обходной путь tail), потому tailчто все равно потребовали бы, чтобы я где-то хранил все данные (если я захочу заглянуть и бросить смотреть на это), и pruneдолжен переписать файл, предположительно (я признаю, что я не пробовал / не доказал это), нарушая перенаправление процесса, генерирующего весь вывод.

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

Итак: есть ли такая вещь, и если да, то что это?

TJ Crowder
источник
1
То, что вы описываете, это «кольцевой буфер» или «кольцевой буфер». Я не знаю каких-либо инструментов командной строки для поддержки такой вещи, хотя это было бы тривиально для создания.
Шон Дж. Гофф
2
Ознакомьтесь с решениями, описанными в разделе «Неблокирующая Linux fifo (по запросу)», stackoverflow.com/questions/7360473/… .
1
Похоже, что это было решено на StackOverflow: stackoverflow.com/questions/7360473/…
Джеймс Блэкберн
@JamesBlackburn: Спасибо! Очень интересно.
TJ Crowder

Ответы:

16

Я думаю, что вы ищете GNU screen. Он поддерживает буфер для полного сохранения последнего экрана или двух выходных данных одной или нескольких программ и позволяет вам отключиться и вернуться позже.

psusi
источник
+1 за предложение экрана. Кстати, вы можете настроить его для хранения большого количества «линий истории».
г-н Шунц
1
Благодарю. Можете ли вы привести пример того, как вы примените это к командам, которые я показал в моем вопросе? На странице руководства написано, что это оконный менеджер (я думаю, что они имеют в виду терминальный смысл, а не графический, но все же). И смогу ли я по-прежнему заходить (через ssh) и выпадать по мере необходимости? (Например, ops на удаленных серверах.)
TJ Crowder,
Да, вы можете использовать экран GNU таким образом. Вы должны создать новый (потенциально именованный) сеанс, выполнить команду внутри этого сеанса и затем отключиться.
TML
2
Есть также tmuxи dtach- все в одном и том же классе терминального мультиплексора / приложения диспетчера сеансов должно быть в состоянии достигнуть того же самого.
jw013
5

Вы можете использовать pv, это обеспечивает столько буферизации, сколько вы хотите в конвейере. Вы можете использовать это так:

sprewingprocess | pv -B 1g > ordinaryfifo &

Это даст вам до 1 ГБ буферизации между spewingprocessи fifo. Большинство дистрибутивов Linux предлагают pvв пакете под названием, хотите верьте, хотите нет pv.

Дэвид Шварц
источник
Спасибо, но разве этот блок не будет заполнен, если буфер заполнен, если я не читаю целевой именованный канал?
TJ Crowder
1
Да, но какой у вас есть выбор? В конечной вселенной вы не можете иметь буквально неограниченную буферизацию.
Дэвид Шварц
Другой выбор, как я описал в моем вопросе: не хранить все выходные данные. Когда буфер заполнен, самые старые вещи выбрасываются.
TJ Crowder
Хм, я проверял это, и это, к сожалению, не совсем работает. Если процесс, читающий fifo, на некоторое время прекращает чтение, pv блокирует попытку записи в fifo, и поскольку он не многопоточный, он также блокирует чтение данных в буфер pv. Таким образом, буфер pv будет продолжать заполняться, пока процесс чтения fifo продолжает читать. pv может читать и буферизовывать некоторые данные, но это не мешает писателю полностью блокировать.
Даниэль С. Стерлинг
1

У меня такая же проблема. Это мое первое решение. Сначала запишите выходные данные в файл, который мы усекаем после каждой строки, чтобы он не рос бесконечно:

spewingprocess | while read line; do echo $line > buffer.txt ; done

Затем прочитайте из файла, используя tail (где 2> /dev/nullизбавляется от сообщения об ошибке «file truncated»):

tail -f ./buffer.txt 2> /dev/null

Таким образом, буфер не растет, и мы можем мультиплексировать, например, запускать столько хвостов, сколько захотим. Однако проблема этого подхода заключается в том, что мы можем потерять данные, когда усечем их быстрее, чем может прочитать хвост, как показывает этот тест:

for ((i=0; ; i++)) ; do echo "$i" ; done | while read line; do  echo $line > buffer.txt ; done
tail -f ./buffer.txt 2> /dev/null > log.txt

После запуска в течение некоторого времени первая и последняя строки:

$ head -n 1 log.txt
0
$ tail -n 1 log.txt
78783

Но в файле меньше строк, поэтому некоторые теряются:

$ wc log.txt
67087  67087 392819 log.txt

Тем не менее, это кажется хорошим решением, если вы не очень заботитесь о потере данных или когда ваш процесс выброса недостаточно быстр для потери данных.

bterwijn
источник