Команда bash для создания массива с 10 самыми последними изображениями в каталоге?

В RedHat/CentOS значение по умолчанию равно 60.
"Для улучшения производительности" - это очень широкое понятие. Какую производительность вы пытаетесь улучшить?

Есть ли у вас проблемы с нехваткой памяти?
Делает ли ваша система SWAP, когда еще есть свободная память/кэш-память?

В Linux свободная RAM = потраченная RAM, поэтому почти вся свободная память используется для дискового кэша.
Есть случаи с swappiness=60, когда страницы в памяти перемещаются в SWAP, если к ним не обращались в течение длительного времени, независимо от того, что у вас есть нераспределенная оперативная память.
Перемещение некоторых страниц памяти в SWAP не обязательно плохо.

Пожалуйста, пролейте больше света на ваш вопрос для более подробного ответа.

3
15.04.2019, 17:07
4 ответа

Правильный синтаксис::

list=($(ls -t *.jpg *.png | head -10))
echo First element: ${list[0]}
echo Last element: ${list[9]}

Однако это решение будет иметь проблемы с именами файлов, содержащими символы пробела (или вообще любые пробелы ).

4
27.01.2020, 21:12

Для bash≥ 4:

Чтобы прочитать вывод команды в массив построчно, вы должны использоватьreadarray:

readarray files < <(ls -1t *.jpg *.png | head -10)

... илиmapfile:

mapfile -t files < <(ls -1t *.jpg *.png | head -10)

иначе:

files=()
while IFS= read -r f; do
    files+=( "$f" )
done < <(ls -1t *.jpg *.png | head -10)

См. также .


Но имена файлов могут иметь разрывы строк, поэтому для чтения имен файлов лучше использовать findи использовать разделитель \0вместо ls -1, который использует разделитель \n:

files=()
while IFS=  read -r -d $'\0' f; do
    files+=("$f")
done < <(
    find. -maxdepth 1 -type f \
      -regextype posix-extended -iregex ".*\.(jpg|png)$" \
      -printf '%T@\t%P\0' \
    | sort -nrz \
    | head -z -n 10 \
    | cut -z -f2-
)
3
27.01.2020, 21:12

Вместо синтаксического анализа ls, и если вы можете положиться на внешнюю statутилиту и bash v4+ (для ассоциативных массивов ), вы могли бы собрать список файлов по inode, а затем собрать список самые последние индексные дескрипторы, затем создайте массив имен файлов:

shopt -s nocaseglob extglob
declare -a filesbyinode=()
for f in *.@(jpg|png); do filesbyinode[$(stat -c %i "$f")]=$f; done
[ ${#filesbyinode[@]} -gt 0 ] || return
declare wantedfiles=()
for inodes in $(stat -c '%Y %i' *.@(jpg|png) | sort -k1,1rn | awk '{print $2}' | head -10)
do 
  wantedfiles+=("${filesbyinode[$inodes]}")
done
declare -p wantedfiles

Первый шаг — установить две опции оболочки:

  • nocaseglob--это позволяет подстановочному знаку jpgтакже соответствоватьJPGJpGи...)
  • extglob--это позволяет использовать @(jpg|png), что означает :совпадающие имена файлов могут заканчиваться на jpgилиpng(в соответствии с nocaseglob, выше)

Затем мы создали пустой ассоциативный массив, который индексирует имена файлов по их инодам.

Последующий цикл forстроит массив filesbyinodeс индексами инодов (, результатом выполнения команды stat), и именами файлов в качестве значений.

Если файлов нет, мы спасаемся с помощьюreturn--корректируем это в соответствии с вашей ситуацией (возможно, if/else ).

Затем мы объявляем (обычный массив )для хранения интересующих нас файлов. Следующий цикл forперебирает 10 самых последних инодов и добавляет соответствующие имена файлов в массив. 10 самых последних инодов определяются путем раскрытия того же подстановочного знака, что и раньше, но с запросом только времени модификации (в секундах с начала эпохи )и инодов; после сортировки по времени модификации в поле #1 (самый большой/самый последний первый ), мы отделяем иноды в поле #2 с awkи захватываем 10 лучших из них с head.

В качестве демонстрации того, что код безопасен для файлов с разными именами:

for i in $(seq 1 10); do touch $RANDOM.jpg $RANDOM.png $RANDOM.txt; sleep 1.1; done
touch x.jpg '[x].jpg' 'a?b.jpg' 'a*b.jpg' '$( echo boom ).jpg' 
touch single\'quote.jpg double\"quote back\\slash.jpg '*.jpg' ②.jpg

... вывод:

declare -a wantedfiles=([0]="②.jpg" [1]="*.jpg" [2]="single'quote.jpg" [3]="back\\slash.jpg" [4]=$'X\240Y.jpg' [5]="[x].jpg" [6]="a?b.jpg" [7]="a*b.jpg" [8]="\$( echo boom ).jpg" [9]="25396.jpg")

(изменить последнее имя файла для того, что $RANDOMпридумал ).

-1
27.01.2020, 21:12

Если вариант zsh, то все проще:

set -o nocaseglob
array=( *.(png|jpg)(Om[-10,-1]) )

set -o nocaseglobпозволяет более простому png|jpgсопоставлять варианты регистра, такие как PNGили JpG.

Следующий оператор присваивает массиву результаты генерации очень специфического имени файла (glob ). Слева направо:

  • *.(png|jpg)--расширяется до списка имен файлов, которые заканчиваются на .jpgили .png, в зависимости от случая -параметр чувствительности, который мы включили
  • (Om...)--zsh "квалификатор glob", который говорит сортировать(Order )файлы по времени модификации (от самого старого к самому новому)
  • [-10,-1]--сращивание массива zsh, которое берет десять элементов в конце (десять самых последних файлов)

Как только вы научитесь анализировать синтаксис, zsh упрощает обработку подобных ситуаций, потому что генерация подстановок/имен файлов позаботится об именах файлов за вас --не беспокойтесь о разборе ls. Например, с «забавными» именами файлов, которые я сгенерировал в своем другом ответе , результаты:

$ print -l $array
4521.png
a?b.jpg
$( echo boom ).jpg
a*b.jpg
[x].jpg
X▒Y.jpg
single'quote.jpg
backslash.jpg
②.jpg
*.jpg

(результаты немного отличались в последовательности, потому что некоторые файлы имели одинаковую отметку времени ).

1
27.01.2020, 21:12

Теги

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