Команды 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"
Приведенная выше команда успешно выполняется на всех маленьких файлах, которые я к ней добавляю (маленькие означает <= 15 КБ). Это также успешно, если окончательное появление literal string
находится в начале файла (например, literal string
появляется в верхней части файла и больше нигде). Наконец, это также успешно, когда ни один из {-q
, -m1
} флаги передаются grep
команда.
Тем не менее, когда файл составляет около 680 КБ, и literal string
появляется в конце файла, затем tac
команда выводит "tac: write error" в STDERR. Несмотря на эту ошибку, команда, кажется, успешно выполнила печать соответствующей строки для вывода (когда -q
флаг опускается) и получает соответствующее возвращаемое значение из grep
,
Дальнейшее тестирование показало, что эта же ошибка возникает при использовании cat
кроме literal string
должен появиться в начале файла, чтобы сгенерировать ошибку, а сгенерированная ошибка - "cat: write error: на устройстве не осталось места".
Обратите внимание, что это происходит только если хотя бы один из {-m1
, -q
} параметры передаются в grep
команда, совпадение находится рядом с первой обработанной строкой файла (для cat
это в начале, для tac
это ближе к концу), и файл большой.
Я управлял df
и сообщает о 14 МБ, доступных на диске Cygwin, при этом 60 ГБ свободно на самом диске. Я знаю, что могу просто перенаправить STDERR на устройство NUL, но это выглядит как хакерский обходной путь. Кто-нибудь знает, как это исправить правильно?
НАЧАТЬ РЕДАКТИРОВАТЬ
Я нашел еще одно сообщение об этой же ошибке от мая 2017 года, но решение не было представлено. ОП другого поста действительно указывает, что он думает, что это ограничение размера буфера канала (возможно, в Windows, возможно в Cygwin).
1 ответ
Я обнаружил несколько обходных путей. Просто измените команду:
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
находит первый матч.