Вопрос по unix, bash, cygwin – Чтение имен файлов в массив

51

Я хочу получить список файлов и затем прочитать результаты в массив, где каждый элемент массива соответствует имени файла. Это возможно?

Да, это возможно. Возможно, не рекомендуется, если имена могут содержать произвольные символы (пробелы и новые строки в именах вызывают горе), но это выполнимо. Какую часть руководства вам было трудно понять? Jonathan Leffler

Ваш Ответ

5   ответов
16

arr=( $(ls) )

Хотя используя выводls совсем не безопасно.

Гораздо лучше и безопаснее, чемls ты можешь использоватьecho *:

arr=( * )

echo ${#arr[@]} # will echo number of elements in array

echo "${arr[@]}" # will dump all elements of the array
Согласен, я просто хотел рассказать, как создать массив из некоторого вывода команды. Однако я отредактировал свой ответ, чтобы подчеркнуть, чтоls выхода следует избегать.
Кто-нибудь знает, какое максимальное количество имен файлов / элементов может содержать массив?
Анубхава, пожалуйста, удалитеarr=( $(ls) ) линия. Или, если вы хотите оставить это, пожалуйста, явно добавьте упоминание, какdon't do this, it's broken.
ls не является необходимым и не должно использоваться для этой цели.
Когда расширение массива не заключено в кавычки, все элементы массива представляются в виде строки, а не отдельных элементов массива. Некотируемые${arr[*]} а также${arr[@]} подобные.
3

ls это не путь. Попробуй это:

declare -a FILELIST
for f in *; do 
    #FILELIST[length_of_FILELIST + 1]=filename
    FILELIST[${#FILELIST[@]}+1]=$(echo "$f");
done

Чтобы получить имя файла из массива, используйте:

echo ${FILELIST[x]}

Чтобы получить n имен файлов из массива, начиная с x, используйте:

echo ${FILELIST[@]:x:n}

Для большого учебника по массивам bash, смотрите: http://www.thegeekstuff.com/2010/06/bash-array-tutorial/

Знаете ли вы, что то, что вы делаете, - это неправильный способ просто сделатьFILELIST = ( * )? (или скорееFILELIST += ( * )). С какой стати ты используешь$(echo "$f") вместо просто"$f"?
Вы должны перебрать глобус файлаOR создать массив, используя глобус файла, как в моем ответе - неboth!. При добавлении элементов в массив нет причин использовать длину массива в выражении сложного индекса (с одной стороны, он не будет работать должным образом, если массив будет разреженным).array+=(element), Нет причин использовать$(echo "$f") просто сделайте задание напрямую. Отсутствует закрывающая фигурная скобка на одном из вашихecho заявления.
85

lsэтоне предназначено для этого. Используйте шатание.

shopt -s nullglob
array=(*)
array2=(file*)
array3=(dir/*)

nullglob опция заставляет массив быть пустым, если нет совпадений.

Спасибо, в любом случае я могу передать результаты этих? Я пробовал что-то вроде arr (* | grep & quot; .txt & quot;), но мне это не нравится. dublintech
Вы также можетеappend filenames в массив,output filenames а такжеloop through их.
@dublintech: вам не нужноgrepпросто включите строку в свой глобус:array=(*.txt) или жеarray=(*foo*)
0

pathname expansion (globbing) вот так:

#!/bin/bash
SOURCE_DIR=path/to/source
files=(
   "$SOURCE_DIR"/*.tar.gz
   "$SOURCE_DIR"/*.tgz
   "$SOURCE_DIR"/**/*
)

Выше будет создан массив с именемfiles и добавить к нему N элементов массива, где каждый элемент в массиве соответствует элементу вSOURCE_DIR кончающийся на.tar.gz или же.tgzили любой элемент в его подкаталоге с возможной рекурсией поддиректории, такой как Dennisуказывает на то в комментариях.

Вы можете использоватьprintf чтобы увидеть содержимое массива, включая пути:

printf '%s\n' "${files[@]}" # i.e. path/to/source/filename.tar.gz

Или используяparameter substitution чтобы исключить пути:

printf '%s\n' "${files[@]##*/}" # i.e. filename.tgz
Тебе нужно иметьshopt -s globstar для того, чтобы использовать рекурсивное сглаживание (**).
... количество должно быть достаточно близко, если работает рекурсивное сглаживание. Мои счета в районе 3800.
Я в порядке, оставив это здесь. Это не является специфичным для вопроса OP, но это полезный метод при выводе имен файлов / путей.
hash работает только с внешними исполняемыми файлами (попробуйтеhash -t ls а такжеhelp hash) и не собирается показывать что-либо дляshopt потому что это встроенный или дляglobstar потому что это вариант, а не исполняемый файл. Пытатьсяtype -a shopt показать гдеshopt приходит иshopt Сам по себе, чтобы показать настройки всех ваших вариантов. использованиеecho "$BASH_VERSION" чтобы показать версию вашей в настоящее время запущенной оболочки (если это Bash) и посмотреть выводps -o tty,command чтобы увидеть, действительно ли это/bin/bash, сравнитьfind /usr -type d | wc -l а такжеecho /usr/**/ | tr -cd " " | wc -c ...
Не для меня. И по умолчанию Bash на MacOS 3.2, который не имеетglobstar, Что означает подсчет символов в некоторых именах каталогов сecho /usr/**/ | wc -c выход для вас? На моем Mac, в Сьерре с Bash 3.2 или в Bash 4.4 сglobstar выкл, это выводит 122. Если я запускаю Bash 4.4 сglobstar Я получаю 277904. Последнее явно рекурсивно, а первое - нет. КСТАТИ,shopt определяется, но я предполагаю, что вы имеете в видуglobstar (в Bash 3.2,shopt -p globstar выдает ошибку, в Bash 4.4 она показывает, установлена она или не установлена).
0

path="" # could set to any absolute path
declare -a array=( "${path}"/* )

Я предполагаю, что вы извлечете ненужный материал из списка позже.

Похожие вопросы