Утилита для буферизации неограниченного объема данных в конвейере?

У меня есть это в моем .bashrc, и он хорошо работает.

function cd {
    builtin cd "$@" && ls -F
    }

Ранее в моем .bashrc я имею: [ -z "$PS1" ] && return, и все после той строки только относится к интерактивным сессиям, таким образом, это не влияет как cd ведет себя в сценариях.

12
03.10.2011, 04:02
6 ответов

pv (средство просмотра канала), утилита может сделать это (с -B опция) и намного больше, включая предоставление Вам отчеты о выполнении работ.

12
27.01.2020, 19:54
  • 1
    Существует ли способ сделать это с неограниченным объемом данных? Настолько лучше всего, как я могу сказать, я должен предоставить число-B и если производитель получит это далеко впереди потребителя, то производитель замедлится снова. Если Вы находитесь в ситуации, где существует несколько потребителей (producer | tee >(pv -cB $SIZE | consumer1) | pv -cB $SIZE2 | consumer2), это может вызвать замедление снова. –  Daniel H 17.06.2013, 19:40
  • 2
    я использовал pv сотни времен и никогда не знали это. Очень потрясающий, Спасибо! –  Rucent88 08.08.2014, 19:40
  • 3
    pv -B 4096 -c -N in /dev/zero | pv -q -B 1000000000 | pv -B 4096 -c -N out -L 100k > /dev/null - Я ожидаю обоих pvs на концах, чтобы быть гладким (хотя один являющийся 1 ГБ вперед). Это не прокладывает себе путь, в отличие от этого, с mbuffer –  Vi. 31.12.2015, 00:17

можно использовать dd:

producer | dd obs=64K | consumer

Это доступно на каждом Unix.

9
27.01.2020, 19:54
  • 1
    +1 для использования стандартной утилиты, хотя pv вероятно, вероятно, более хорошо использовать (выставочный прогресс). –  Totor 17.03.2013, 17:17
  • 2
    Это на самом деле отделяет чтение и скорость записи? Это походит dd только хранят один блок за один раз, таким образом, он просто задержал бы все количеством времени, что он берет для создания размера блока; исправьте меня, если я неправ. Кроме того, эта буферизация может быть расширена на неограниченный размер, или независимо от того, что ввело для размера блока? –  Daniel H 17.06.2013, 19:45
  • 3
    @DanielH - он делает теперь. –  mikeserv 31.12.2015, 00:54

Смотрите на mbuffer. Это может буферизовать к памяти или файлу с отображенной памятью (-t/-T).

7
27.01.2020, 19:54
  • 1
    Как я попросил другие, есть ли способ сказать этому буферизовать столько, сколько необходимо, или это имеет максимальный размер? Существует ли концептуальная причина, почему большинство этих программ имеет максимальные размеры и, например, не использует связанный список буферов меньшего размера (или никакая другая реализация очереди произвольного размера)? –  Daniel H 20.06.2013, 01:11
  • 2
    Вероятно, предотвратить ошибки из памяти. Можно, вероятно, использовать опцию установить очень большой буфер (приблизительно 4 ГБ), если Вы хотите так (попробуйте его). –  David Balažic 19.01.2016, 15:13

Это в основном отрицательный ответ. Оказывается, что ни dd, ни mbuffer, ни даже pv не работают во всех случаях, в частности, если скорость генерации данных производителем может сильно варьироваться. Я приведу несколько примеров ниже. После набора команды, подождите около 10 секунд, затем наберите > (чтобы перейти к концу данных, т.е. дождаться конца входных).

zsh -c 'echo foo0; sleep 3; \
        printf "Line %060d\n" {1..123456}; \
        echo foo1; sleep 5; \
        echo foo2' | dd bs=64K | less

Здесь, после набора >, нужно подождать 5 секунд, т.е. продюсер (скрипт zsh) заблокировался до того, как уснул 5. Увеличение размера bs до, например, 32М не меняет поведения, хотя буфер 32МБ достаточно большой. Я подозреваю, что это происходит потому, что dd блокируется на выходе, а не на входе. Использование oflag=nonblock не является решением, так как это отбрасывает данные.

zsh -c 'echo foo0; sleep 3; \
        printf "Line %060d\n" {1..123456}; \
        echo foo1; sleep 5; \
        echo foo2' | mbuffer -q | less

С помощью mbuffer проблема в том, что первая строка (foo0) появляется не сразу. Похоже, что опция включения буферизации строки на входе отсутствует.

zsh -c 'echo foo0; sleep 3; \
        printf "Line %060d\n" {1..123456}; \
        echo foo1; sleep 5; \
        echo foo2' | pv -q -B 32m | less

С pv поведение аналогично dd. Хуже того, я подозреваю, что оно делает неправильные вещи с терминалом, так как иногда меньше невозможно получить входной сигнал от терминала; например, нельзя выйти из него с помощью q.

.
1
27.01.2020, 19:54

Нестандартный ход: использование буферов сокетов.

Пример:

# echo 2000000000 > /proc/sys/net/core/wmem_max
$ socat -u system:'pv -c -N i /dev/zero',sndbuf=1000000000 - | pv -L 100k -c -N o > /dev/null
        i:  468MB 0:00:16 [ 129kB/s] [  <=>                        ]
        o: 1.56MB 0:00:16 [ 101kB/s] [       <=>                   ]

Для этого реализованы два дополнительных инструмента: buffered_pipeline и mapopentounixsocket

$ ./buffered_pipeline ! pv -i 10 -c -N 1 /dev/zero ! $((20*1000*1000)) ! pv -i 10 -L 100k -c -N 2 ! > /dev/zero
        1: 13.4MB 0:00:40 [ 103kB/s] [         <=>      ]
        2: 3.91MB 0:00:40 [ 100kB/s] [         <=>      ]
0
27.01.2020, 19:54

При использовании pvс --buffer-size|-Bвы, вероятно, захотите также использовать параметр --no-splice|-C, чтобы предотвратить использование системного вызова splice(2).

Из справочных страниц pv:

-C, --no-splice
Never  use  splice(2),  even  if it would normally be possible.  The splice(2) system
call is a more efficient way of transferring data from or  to  a  pipe  than  regular
read(2)  and write(2), but means that the transfer buffer may not be used.  This pre‐
vents -A and -T from working, so if you want to use -A or -T then you  will  need  to
use  -C,  at  the  cost  of a small loss in transfer efficiency.  (This option has no
effect on systems where splice(2) is unavailable).

Насколько я знаю, spliceдоступен в Linux, поэтому для использования pvв качестве буфера следует использовать параметр -C.

Следовательно, ваше окончательное решение должно быть примерно таким:

$ producer | pv -C -B 1G | consumer
0
28.01.2021, 08:44

Теги

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