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


20

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

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

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

mkmagicfifo magicfifo 10M
spewingprocess > magicfifo &

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

tail -f magicfifo

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

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

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

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


1
То, что вы описываете, это «кольцевой буфер» или «кольцевой буфер». Я не знаю каких-либо инструментов командной строки для поддержки такой вещи, хотя это было бы тривиально для создания.
— Шон Дж. Гофф

2
Ознакомьтесь с решениями, описанными в разделе «Неблокирующая Linux fifo (по запросу)», stackoverflow.com/questions/7360473/… .

1
Похоже, что это было решено на StackOverflow: stackoverflow.com/questions/7360473/…
— Джеймс Блэкберн

@JamesBlackburn: Спасибо! Очень интересно.
— TJ Crowder

Ответы:


16

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


+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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.