Есть ли способ обойти сломанную трубу?

2

У меня есть каталог с большим количеством файлов.

./I_am_a_dir_with_many_subdirs/

Внутри скрипта я бы хотел найти в нем все подкаталоги, отсортировать их и вывести в массив bash. Итак, я делаю:

SubdirsArray=(`find ./I_am_a_dir_with_many_subdirs/ -maxdepth 2 -mindepth 2 -type d | sort`)

Выполняя скрипт, я получаю следующие сообщения об ошибках:

    sort: write failed: standard output: Broken pipe
    sort: write error

Как объясняется в этом посте : вероятно, sortвыполняет и закрывает канал перед findзавершением записи в него. Таким образом, команда write (), инициированная findEPIPE, получает ошибку «Broken pipe», ОС отправляет findSIGPIPE. Прежде чем SIGPIPE достигает find, он печатает сообщение об ошибке, затем получает SIGPIPE и умирает.

Вопросов:

  1. Итак, что SubdirsArrayсодержит мой ? Субдиры, которые findнашли, но sortоставили несортированными?

  2. Если так, то как быть с этой проблемой с сломанными трубами? Заставить find записать его результаты во временный файл, а затем заставить sort прочитать его?

    Я не понимаю, почему «это также не о чем беспокоиться», если это происходит в неинтерактивной оболочке: почему? My SubdirsArrayсодержит что-то несортированное и далее в скрипте, я предполагаю, что его элементы отсортированы ?!

  3. Я получаю два сообщения об ошибках:

    sort: write failed: standard output: Broken pipe
    sort: write error
    

В этой теме предполагается, что sortво временной директории недостаточно места для сортировки всех входных данных. Но разве это не значит, что этот сорт получил что-то от find?!? Я в замешательстве ... В любом случае, я пытался использовать

SubdirsArray=(`find ./I_am_a_dir_with_many_subdirs/ -maxdepth 2 -mindepth 2 -type d | sort -T /home/temp_dir`)

но это не помогло

PS

Я не уверен, важно ли это, но я использую find|sortв многопроцессорном сценарии: несколько процессоров одновременно выполняют одну и ту же команду в подоболочках.

user1541776
источник
sortничего не может сделать, прежде чем он прочитает ввод полностью, и, кроме того, если бы он sortзаканчивался преждевременно, он бы findсообщал о сломанной трубе, а не sort. Ошибка в другой теме, которую вы упоминаете, выглядит совсем иначе и действительно отличается.
Ян Худек
@JanHudec спасибо, что указали на это, я не обращал внимания на то, какая команда сообщила о проблеме.
user1541776

Ответы:

2
sort: write failed: standard output: Broken pipe

Проблема не между findа sort. sortИмеет проблемы с выходом , а это значит , оболочка не хочет читать длинный список в переменной.

Вам придется обрабатывать ввод с помощью while read…, сохраняя его во временном файле, если он вам нужен более одного раза. С дополнительным преимуществом, это разделяется только на новую строку, поэтому он правильно обрабатывает имена файлов с пробелами, которых нет в подходе backtick.

К сожалению, вы не говорите, как вы хотите использовать результат, я не могу сказать вам, как именно переписать его.

Обратите внимание, что массивы не являются частью спецификации оболочки POSIX, и есть оболочки, которые заметно быстрее, чем bash, но не имеют их. Вот почему многие люди, включая меня, часто избегают использовать их в сценариях.

Ян Худек
источник
Ян, спасибо за ответ и комментарий. Я хотел бы использовать SubdirsArrayдля цикла. Итак, я буду реализовывать ваше решение, как: find ./I_am_a_dir_with_many_subdirs/ -maxdepth 2 -mindepth 2 -type d | sort > temp.txt; while read Subdir; do myFunction $Subdir; done; rm temp.txtВ конце я хотел бы обратиться myFunctionко всем Subdirs. Чтобы сделать это быстрее, я пытаюсь распараллелить мой код и использовать Nподоболочки с wait. Каждый подоболочек должен занимать только часть Subdirs. Я не хотел отправлять длинный массив подкаталогов, которые он должен обрабатывать для каждой подоболочки, но первый / последний индекс SubdirsArray.
user1541776
@ user1541776: Не забудьте перенаправить ввод в цикл. Это может быть сделано даже без временного файла, но, вероятно, нет, если вы хотите сначала разбить его.
Ян Худек
Вы имеете в виду find ./I_am_a_dir_with_many_subdirs/ -maxdepth 2 -mindepth 2 -type d | sort > temp.txt; while read Subdir; do myFunction $Subdir; done <"temp.txt" ; rm temp.txt?
user1541776
@ user1541776: Да, именно так. readпросто читает со стандартного ввода.
Ян Худек
@ user1541776: Вы также можете передать в цикл, но он будет работать в подоболочке, в оболочке, в которой он есть (например, bash, но не ash / dash), вы можете использовать подстановку процесса, то есть like <(find ... | sort).
Ян Худек