Bash: канал 'find' выводит в 'readarray'

14

Я пытаюсь найти файлы с помощью findи поместить эти файлы в массив Bash, чтобы я мог выполнять над ними другие операции (например, lsили grepих). Но я не могу понять, почему readarrayне читает findвывод, так как он передается по нему.

Скажем, у меня есть два файла в текущем каталоге, file1.txtи file2.txt. Таким образом, findвывод выглядит следующим образом:

$ find . -name "file*"
./file1.txt
./file2.txt

Поэтому я хочу передать это в массив, двумя элементами которого являются строки "./file1.txt"и "./file2.txt"(без кавычек, очевидно).

Я пробовал это, среди прочего:

$ declare -a FILES
$ find . -name "file*" | readarray FILES
$ echo "${FILES[@]}"; echo "${#FILES[@]}"

0

Как видно из echoвывода, мой массив пуст.

Так что именно я здесь делаю не так? Почему readarrayне считывать findвывод в качестве стандартного ввода и помещать эти строки в массив?

villapx
источник

Ответы:

21

При использовании конвейера bash запускает команды в подоболочках. Таким образом, массив заполняется, но в подоболочке, поэтому родительская оболочка не имеет к нему доступа.

Используйте процесс подстановки:

readarray FILES < <(find)

Обратите внимание, что это не работает для файлов с символами новой строки в их именах. Если это так, вам нужен более сложный синтаксис:

readarray -d '' < <(find -print0)
choroba
источник
3
Для того, чтобы поддержать переводы строк, этого достаточно:readarray -d '' < <(find your_args -print0)
ВасяНовиков
6

Правильное решение:

unset a; declare -a a
while IFS= read -r -u3 -d $'\0' file; do
    a+=( "$file" )        # or however you want to process each file
done 3< <(find /tmp -type f -print0)

Это похоже на то, что Greg BashFAQ 020 подробно объясняет, и этот ответ охватывает .

Не имеет проблем с нечетными именованными файлами (которые не содержат NUL в имени), с пробелами или новыми строками. И результат устанавливается в массиве, что делает его полезным для дальнейшей обработки.

Сообщество
источник
Отлично, это лучшее решение проблемы, которую я пытался решить в первую очередь. +1, как только мой представитель достигнет 15 :)
villapx
3

readarray также можно читать со стандартного ввода

readarray FILES <<< "$(find . -name "file*")"; echo "${#FILES[@]}"
smac89
источник
Это не работает find -print0для защиты от "неожиданных" имен файлов.
roaima