Как исправить ошибку “Broken Pipe” при использовании awk с head

Вопрос или проблема

Я получаю ошибки “broken pipe” от команды, которая делает что-то вроде:

ls -tr1 /a/path | awk -F '\n' -vpath=/prepend/path/ '{print path$1}' | head -n 50

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

Кажется, что происходит следующее: вывод корректен (я получаю 50 пути к файлам), но когда команда head выводит 50 файлов, она закрывает stdin, вызывая ошибку “broken pipe” в awk, так как он продолжает выводить дополнительные строки.

Решение от автора вопроса, ревизия 2


Во-первых, нет необходимости заставлять awk добавлять путь к каждому файлу, чтобы затем отбросить большую часть из них. Поэтому, команда awk должна быть последней в пайпе.

Во-вторых, вместо использования обратной сортировки с ls, можно использовать стандартную сортировку по времени и затем использовать tail для извлечения нужных строк. Это гарантирует, что пайп останется открытым на протяжении всего процесса.

Новая команда будет выглядеть следующим образом:

ls -t1 /a/path | tail -n 50 | awk -F '\n' -vpath=/prepend/path/ '{print path$1}'

Ответ или решение

Как исправить ошибку "Broken Pipe" при использовании awk с head

В Unix-подобных системах ошибка "Broken Pipe" часто возникает при использовании связки команд через конвейер (pipe). Это происходит, когда одна из команд завершает выполнение до того, как другая завершила обработку данных. Рассмотрим ситуацию, в которой ошибка появляется при использовании следующей команды:

ls -tr1 /a/path | awk -F '\n' -vpath=/prepend/path/ '{print path$1}' | head -n 50

Проблема и ее причины

Главная причина ошибки "Broken Pipe" в данном контексте заключается в работе команды head. После вывода первых 50 строк head закрывает входной поток, что делает дальнейшую передачу данных из awk невозможной. В результате awk пытается отправить больше данных, но конвейер уже закрыт, что и приводит к ошибке.

Решение проблемы

Чтобы избежать ошибки "Broken Pipe", необходимо изменить порядок выполнения команд и оптимизировать их использование. Проблема может быть решена следующим образом:

  1. Оптимизация команды awk: Использование awk для обработки всего вывода, лишь чтобы затем отбросить большую его часть, нецелесообразно. Логичнее перенести awk в конец цепочки команд.

  2. Изменение порядка сортировки: Вместо использования ls -tr1, который сортирует файлы в обратном порядке и затем выводит их, можно использовать стандартную сортировку по времени (ls -t1) и воспользоваться командой tail.

Новый и более эффективный вариант команды будет выглядеть так:

ls -t1 /a/path | tail -n 50 | awk -F '\n' -vpath=/prepend/path/ '{print path$1}'

Пояснение выбранного решения

  1. Сначала отсортируйте: Команда ls -t1 /a/path сортирует файлы по времени последней модификации, начиная с самых новых. Эта сортировка более естественна и позволяет сразу работать с самыми новыми файлами без необходимости инвертирования порядка.

  2. Ограничение вывода командой tail: Использование tail -n 50 позволяет выбрать последние 50 строк из предварительно отсортированного списка, эффективно имитируя вывод самых старых файлов.

  3. Нанесение модификации: После выполнения двух предыдущих шагов, команда awk добавляет необходимый префикс только к тем файлам, которые вам нужны, тем самым исключая необходимость добавления префикса ко всем файлам и их повторной обработки.

Вывод

Применив данное решение, вы минимизируете вероятность возникновения ошибки "Broken Pipe" и улучшите производительность своей утилиты за счёт более корректного использования командной обработки. Подобное решение эффективно, так как исключает избыточные операции и ограничивает поток данных именно на этапе, где его объём становится управляемым.

Использование такой оптимизации не только убережет вашу систему от ошибок, но и улучшит читаемость и эффективность вашего скрипта.

Оцените материал
Добавить комментарий

Капча загружается...