#arrays #bash #shell #command-line
#массивы #bash #shell #командная строка
Вопрос:
Я получаю 15 самых последних .jpg
или .png
файлов из текущего каталога в массиве:
images=$(ls -1tr *.jpg *.png | tail -n 15)
Похоже, в данном случае это работает нормально:
for i in ${images[*]}; do echo "Found this image: $i"; done
Он показывает мне 15 строк как:
Найдено это изображение: foo.jpg
Найдено это изображение: bar.png
Найдено это изображение: baz.jpg
(… и т.д….)
Однако, когда я пытаюсь напечатать длину $images
массива следующим образом:
echo ${#images[@]}
Я всегда получаю:
1
Несмотря на то, что найдено несколько изображений, и приведенный выше for
цикл над $images
массивом действительно показывает несколько строк.
Что я делаю не так? Как мне получить количество элементов в массиве?
Комментарии:
1. Вы не определяли массив; вы определили обычную переменную с одной строкой, которая содержит встроенные символы новой строки.
2. И определение массива таким образом —
images=( $(ls -1tr *.jpg *.png | tail -n 15) )
— может привести к сбою, поскольку замена команды может привести как к разбиению слов, так и к расширению имени пути.
Ответ №1:
Вы правильно получаете количество элементов, и оно действительно равно 1.
Поскольку вы знаете JS, вот ваш код на JavaScript, чтобы увидеть, что происходит на самом деле:
// Assign all filenames to a single index
var images = ["foo.jpgnbar.jpgnbaz.jpg"]
// Join all the elements on spaces, then split them up on whitespace
var elements = images.join(" ").split(/[ tn]/);
for (var i in elements) {
console.log("Found this image: " elements[i]);
}
console.log("Array length: " images.length);
Вывод:
Found this image: foo.jpg
Found this image: bar.jpg
Found this image: baz.jpg
Array length: 1
Вот что вы вместо этого хотели сделать в Bash:
images=( $(ls -1tr *.jpg *.png | tail -n 15) )
for i in "${images[@]}"; do echo "Found this image: $i"; done
echo "${#images[@]}"
Хотя разбор ls
выходных данных считается хрупким: приведенный выше код по-прежнему разбивается на пробелы, поэтому My Image.jpg
он превратится в My
и Image.jpg
.
К сожалению, простой и удобной замены, когда вам нужны файлы, отсортированные по дате изменения, нет, но это позволяет избежать проблем, когда файлы содержат *
пробелы или (Bash 4 ):
mapfile -t images < <(ls -tr *.jpg *.png | tail -n 15)
for i in "${images[@]}"; do echo "Found this image: $i"; done
echo "${#images[@]}"
Комментарии:
1. Будьте внимательны: последнее по-прежнему завершается ошибкой, если имена файлов могут содержать новые строки (что случается редко, но стоит упомянуть для полноты картины).