Обновление 2020 для пользователей Linux:
Если у вас есть версия уточненного Баша (4,4-альфа или лучше), как вы , вероятно , делать , если вы на Linux, то вы должны использовать ответ Benjamin W. в .
Если вы работаете в Mac OS, которая, как я проверял в последний раз, по-прежнему использует bash 3.2 или иным образом использует более старую версию bash, переходите к следующему разделу.
Ответ для bash 4.3 или более ранней версии
Вот одно из решений для получения вывода findв bashмассив:
array=()
while IFS= read -r -d $'\0'; do
array+=("$REPLY")
done < <(find . -name "${input}" -print0)
Это сложно, потому что, как правило, имена файлов могут содержать пробелы, новые строки и другие символы, враждебные скрипту. Единственный способ использовать findи безопасно отделить имена файлов друг от друга - использовать, -print0который печатает имена файлов, разделенные нулевым символом. Это не было бы большим неудобством, если бы функции readarray/ mapfileфункции bash поддерживали строки, разделенные нулем, но это не так. Bash readделает это, и это приводит нас к описанному выше циклу.
[Этот ответ был первоначально написан в 2014 году. Если у вас установлена последняя версия bash, см. Обновление ниже.]
Как это работает
Первая строка создает пустой массив: array=()
Каждый раз, когда выполняется readинструкция, из стандартного ввода считывается имя файла, разделенное нулем. -rОпция указывает , readчтобы оставить символы обратной косой черты в одиночку. -d $'\0'Говорит о readтом , что вход будет нулевым разделены. Поскольку мы не указываем имя read, оболочка помещает ввод в имя по умолчанию:REPLY .
array+=("$REPLY")Оператор присоединяет новое имя файла в массивarray .
Последняя строка объединяет перенаправление и подстановку команд, чтобы обеспечить вывод findна стандартный ввод whileцикла.
Зачем использовать замещение процесса?
Если бы мы не использовали подстановку процесса, цикл можно было бы записать так:
array=()
find . -name "${input}" -print0 >tmpfile
while IFS= read -r -d $'\0'; do
array+=("$REPLY")
done <tmpfile
rm -f tmpfile
В приведенном выше примере вывод findсохраняется во временном файле, и этот файл используется как стандартный ввод для цикла while. Идея замены процесса состоит в том, чтобы сделать такие временные файлы ненужными. Итак, вместо того, чтобы whileполучать стандартный ввод цикла tmpfile, мы можем заставить его получать свой стандартный ввод из<(find . -name ${input} -print0) .
Замена процесса широко используется. Во многих местах, где команда хочет читать из файла, вы можете указать замену процесса <(...)вместо имени файла. Существует аналогичная форма, >(...)которая может использоваться вместо имени файла, в котором команда хочет записать в файл.
Как и массивы, подстановка процессов - это функция bash и других расширенных оболочек. Это не часть стандарта POSIX.
Альтернатива: lastpipe
При желании lastpipeможно использовать вместо процесса подстановку (подсказка: Цезарь ):
set +m
shopt -s lastpipe
array=()
find . -name "${input}" -print0 | while IFS= read -r -d $'\0'; do array+=("$REPLY"); done; declare -p array
shopt -s lastpipeсообщает bash выполнить последнюю команду конвейера в текущей оболочке (не в фоновом режиме). Таким образом, arrayостатки остаются в наличии после завершения конвейера. Поскольку lastpipeдействует только в том случае, если отключено управление заданиями, мы запускаем set +m. (В сценарии, в отличие от командной строки, управление заданиями по умолчанию отключено.)
Дополнительные примечания
Следующая команда создает переменную оболочки, а не массив оболочки:
array=`find . -name "${input}"`
Если вы хотите создать массив, вам нужно будет заключить в скобки результат поиска. Итак, наивно, можно было:
array=(`find . -name "${input}"`)
Проблема в том, что оболочка выполняет разбиение слов на результаты, findпоэтому не гарантируется, что элементы массива будут такими, как вы хотите.
Обновление 2019
Начиная с версии 4.4-alpha, bash теперь поддерживает -dопцию, так что вышеупомянутый цикл больше не нужен. Вместо этого можно использовать:
mapfile -d $'\0' array < <(find . -name "${input}" -print0)
Для получения дополнительной информации об этом, смотрите (и upvote) ответ Benjamin W. в .