Необходимо обрабатывать файлы в текущем каталоге по одному. Я ищу способ получить вывод ls
или find
и сохранить полученное значение как элементы массива. Таким образом, я могу манипулировать элементами массива по мере необходимости.
Как получить вывод команды ls или find, чтобы сохранить все имена файлов в массиве?
Ответы (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)
read -r -d $'\0'
указывает команде read
не рассматривать обратную косую черту как специальный escape-символ и разделять каждое слово символом NUL, поскольку мы сказали find
использовать его в качестве разделителя с -print0
. Часть IFS=
по существу сбрасывает специальную переменную среды внутреннего разделителя полей, поэтому она не будет выполнять разбиение слов на табуляции, пробелы или новые строки. Версия TLDR заключается в том, что эти команды делают так, что вы можете перебирать любое имя файла, независимо от того, какие символы оно содержит.
- person SiegeX; 30.11.2014
IFS=
перед while: IFS = ; while ...
?
- person ; 28.04.2016
find ... | while ....
?
- person ; 28.04.2016
for i in `ls`; do echo $i; done;
проще некуда!
редактировать: хм - согласно комментарию Денниса Уильямсона, кажется, вы можете!
редактировать 2: хотя ОП специально спрашивает, как анализировать вывод ls
, я просто хотел указать, что, как сказали ниже комментаторы, правильный ответ - «вы этого не сделаете». Вместо этого используйте for i in *
или аналогичный.
for i in *
еще проще!
- person Dennis Williamson; 13.01.2011
for i in *; do ...
делает то же самое, за исключением того, что его не путают забавные символы в имена файлов и работает быстрее (потому что не порождает другой процесс).
- person Gordon Davisson; 13.01.2011
*
: for in in $path/*
- person PHP Learner; 25.08.2015
for f in "$path"/*
- person Dennis Williamson; 25.08.2015
for i in *; do echo "$i" done
выведет *
в пустой каталог.
- person Alois Mahdal; 15.06.2017
*
это означает, что файлов нет). Во многих случаях это приводит к ошибке типа «файл не найден», что, если вы хотите. Но если это проблема в вашем сценарии, либо используйте 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.
%files
должно быть $files
. Кроме того, если у вас есть Bash 4.X, вы можете установить shopt -s globstar
и использовать for files in **; do
для рекурсии; полностью отказаться от использования find
- person SiegeX; 13.01.2011
В зависимости от того, что вы хотите сделать, вы можете использовать xargs:
ls directory | xargs cp -v dir2
Например. xargs будет действовать на каждый возвращаемый элемент.
cp
поддерживает это, вы можете использовать xargs cp -v --target-drectory dir2
.
- person Dennis Williamson; 13.01.2011
find ... -print0 | xargs -0
исправит это. Как именно портится? Меня устраивает.
- person Dennis Williamson; 13.01.2011