Как получить вывод команды ls или find, чтобы сохранить все имена файлов в массиве?

Необходимо обрабатывать файлы в текущем каталоге по одному. Я ищу способ получить вывод ls или find и сохранить полученное значение как элементы массива. Таким образом, я могу манипулировать элементами массива по мере необходимости.


person fzkl    schedule 13.01.2011    source источник
comment
@ SiegeX Как мне принять ответы? Я ответил и поблагодарил тех, кто ответил лучше всего, и проголосовал за них, когда я получил привилегию. Что еще я могу сделать?   -  person fzkl    schedule 14.01.2011


Ответы (4)


Чтобы ответить на ваш точный вопрос, используйте следующее:

arr=( $(find /path/to/toplevel/dir -type f) )

Пример

$ find . -type f
./test1.txt
./test2.txt
./test3.txt
$ arr=( $(find . -type f) )
$ echo ${#arr[@]}
3
$ echo ${arr[@]}
./test1.txt ./test2.txt ./test3.txt
$ echo ${arr[0]}
./test1.txt

Однако, если вы просто хотите обрабатывать файлы по одному, вы можете либо использовать опцию find -exec, если сценарий несколько прост, либо вы можете сделать цикл по тому, что возвращает find, например:

while IFS= read -r -d $'\0' file; do
  # stuff with "$file" here
done < <(find /path/to/toplevel/dir -type f -print0)
person SiegeX    schedule 13.01.2011
comment
Это то, что я искал. Спасибо. - person fzkl; 13.01.2011
comment
@ChandanChoudhury read -r -d $'\0' указывает команде read не рассматривать обратную косую черту как специальный escape-символ и разделять каждое слово символом NUL, поскольку мы сказали find использовать его в качестве разделителя с -print0. Часть IFS= по существу сбрасывает специальную переменную среды внутреннего разделителя полей, поэтому она не будет выполнять разбиение слов на табуляции, пробелы или новые строки. Версия TLDR заключается в том, что эти команды делают так, что вы можете перебирать любое имя файла, независимо от того, какие символы оно содержит. - person SiegeX; 30.11.2014
comment
Будет ли работать, если переместить IFS= перед while: IFS = ; while ... ? - person ; 28.04.2016
comment
Кроме того, есть ли разница между этой структурой управления и использованием канала: find ... | while ....? - person ; 28.04.2016

for i in `ls`; do echo $i; done;

проще некуда!

редактировать: хм - согласно комментарию Денниса Уильямсона, кажется, вы можете!

редактировать 2: хотя ОП специально спрашивает, как анализировать вывод ls, я просто хотел указать, что, как сказали ниже комментаторы, правильный ответ - «вы этого не сделаете». Вместо этого используйте for i in * или аналогичный.

person simon    schedule 13.01.2011
comment
for i in * еще проще! - person Dennis Williamson; 13.01.2011
comment
Не анализировать ls! for i in *; do ... делает то же самое, за исключением того, что его не путают забавные символы в имена файлов и работает быстрее (потому что не порождает другой процесс). - person Gordon Davisson; 13.01.2011
comment
@DennisWilliamson Есть ли способ использовать переменную (содержащую путь) вместо *: for in in $path/* - person PHP Learner; 25.08.2015
comment
@PHPLearner: Да. Так же, как вы написали, но вы должны указать переменную. for f in "$path"/* - person Dennis Williamson; 25.08.2015
comment
@GordonDavisson for i in *; do echo "$i" done выведет * в пустой каталог. - person Alois Mahdal; 15.06.2017
comment
@АлоисМахдал Да; Расширение глобуса оболочки оставляет глобус в покое, если нет соответствующих файлов (с * это означает, что файлов нет). Во многих случаях это приводит к ошибке типа «файл не найден», что, если вы хотите. Но если это проблема в вашем сценарии, либо используйте shopt -s nullglob перед ним (и shopt -u nullglob после, чтобы избежать проблем позже), либо в цикле вы можете добавить if [[ ! -e "$i" ]]; then continue; fi в начале цикла, чтобы он пропустил несуществующие файлы. - person Gordon Davisson; 15.06.2017

На самом деле вам не нужно использовать ls/find для файлов в текущем каталоге.

Просто используйте цикл for:

for files in *; do 
    if [ -f "$files" ]; then
        # do something
    fi
done

И если вы хотите также обрабатывать скрытые файлы, вы можете установить относительную опцию:

shopt -s dotglob

Эта последняя команда работает только в bash.

person marco    schedule 13.01.2011
comment
%files должно быть $files. Кроме того, если у вас есть Bash 4.X, вы можете установить shopt -s globstar и использовать for files in **; do для рекурсии; полностью отказаться от использования find - person SiegeX; 13.01.2011
comment
Спасибо! Я исправил ошибку; кстати, у меня есть Bash 4, но у ОП (или у других ридеров тоже) его может и не быть :) - person marco; 13.01.2011

В зависимости от того, что вы хотите сделать, вы можете использовать xargs:

ls directory | xargs cp -v dir2

Например. xargs будет действовать на каждый возвращаемый элемент.

person TyrantWave    schedule 13.01.2011
comment
@Fritschy: Если ваш cp поддерживает это, вы можете использовать xargs cp -v --target-drectory dir2. - person Dennis Williamson; 13.01.2011
comment
@Dennis: да ;) но его там все еще нет ;) - person Marcus Borkenhagen; 13.01.2011
comment
@Fritschy: Одним из источников сбоя может быть наличие пробелов в именах файлов. Использование find ... -print0 | xargs -0 исправит это. Как именно портится? Меня устраивает. - person Dennis Williamson; 13.01.2011