Назад | Перейти на главную страницу

Cygwin 2.9.0 команды cat / tac не работают с большими файлами при подключении к grep -q -m1

Я наблюдаю странное поведение при использовании Cygwin x64 2.9.0 в Windows 10 Pro x64. Команда, которую я пытаюсь запустить, следующая:

tac <file> | grep -q -m1 -F "literal string"

Вышеупомянутая команда успешно обрабатывает все мелкие файлы, которые я ей добавляю (small означает <= 15kB). Также успешно, если последнее появление literal string находится рядом с началом файла (например, literal string появляется в верхней части файла и больше нигде). Наконец, это также удается, когда ни один из {-q, -m1} flags передается в grep команда.

Однако, если размер файла составляет около 680 КБ, а literal string появляется ближе к концу файла, затем tac команда выводит "tac: write error" в STDERR. Несмотря на эту ошибку, команда, похоже, прошла успешно, соответствующая строка выводится на печать (когда -q флаг опущен) и получение соответствующего возвращаемого значения из grep.

Дальнейшее тестирование показало, что эта же ошибка возникает при использовании cat, кроме literal string должен появиться рядом с началом файла, чтобы сгенерировать ошибку, а сгенерированная ошибка - «cat: ошибка записи: на устройстве не осталось места».

Обратите внимание, что это происходит, только если хотя бы один из {-m1, -q} параметры передаются в grep команда, совпадение находится рядом с первой обработанной строкой файла (для cat это близко к началу, ибо tac это ближе к концу), и файл большой.

Я запустил df и сообщает, что на диске Cygwin доступно 14 МБ, а на фактическом диске - 60 ГБ. Я знаю, что могу просто перенаправить STDERR на устройство NUL, но это похоже на хакерский обходной путь. Кто-нибудь знает, как это правильно исправить?

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

я нашел другой отчет той же ошибки с мая 2017 года, но решение не было представлено. OP другого сообщения действительно указывает, что он думает, что это ограничение размера буфера канала (возможно, в Windows, возможно, в Cygwin).

Я обнаружил несколько обходных путей. Просто измените команду:

tac <file> | grep -q -m1 -F "literal string"

одному из:

bash -c "tac <file> | grep -q -m1 -F 'literal string'"
stdbuf -o L tac <file> | grep -q -m1 -F "literal string"

Я думаю, что первый работает, потому что он использует канал Linux, а второй, потому что он заставляет tac вывод команды должен быть буферизован по строке. Обе эти формы позволяют устранить ошибку.

Поскольку это работает, я предполагаю, что проблема в том, что grep прекращает обработку входного буфера, как только находит первое совпадение, но tac продолжает обрабатывать ввод. Как только буфер заполнится (вероятно, 64 КБ), буфер блокируется и tac выходит с указанной ошибкой. Однако поскольку tac успешно обработал нужную мне строку до сбоя, все работает как задумано.

Выбор времени для этих параметров указывает на то, что вызов bash это более быстрый вариант. Вероятно, это связано с тем, что при использовании канала Linux tac может вернуться сразу один раз grep находит первое совпадение.