Я наблюдаю странное поведение при использовании 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
находит первое совпадение.