Bash: Скопируйте n файлов для каждого года рождения в имя файла

У меня есть тысячи фотографий с указанием года рождения в имени файла. Мне нужно найти и скопировать не менее 100 файлов на каждый год рождения, скажем, 100 файлов на 2000 год рождения, 100 файлов на 2001 год, ... и так далее.

Вот формат имен файлов:

35077502_1995-02-01_2012.jpg

Думаю, 2012 год - год, когда была сделана фотография.

Можно ли это сделать с помощью сценария bash?

Спасибо

-1
07.08.2017, 07:05
2 ответа

Если в именах файлов нет гадостей, то можно сделать

for year in 2000 2001; do
  cp `ls *${year}*.jpg|head -n 100` destination
done
1
28.01.2020, 05:07
#!/bin/bash

IFS=$'\n' years=( $(find. -maxdepth 1 -name '*.jpg' -print0 | 
                    sed -zEn 's/^.*_([0-9][0-9][0-9][0-9])-.*\.jpg/\1/p' | 
                    tr '\0' '\n' | 
                    sort -u)
                )

for year in "${years[@]}" ; do
  mkdir -p "$year"
  find. -iname "*_${year}-*.jpg" -size +1k -print0 |
    head -z -n 100 |
    xargs -0r cp -t "$year"
done

Это создает массив ($years), содержащий уникальный набор из 4 -цифр года, извлеченных из имен файлов в текущем каталоге, где году предшествует символ подчеркивания (_), а за ним следует тире(-). Для этого требуется версия GNU sedдля опции -z, также известной как --null-data.

Для каждого года сначала создается каталог для этого года, если он еще не существует, а затем используется findдля перечисления всех имен файлов, соответствующих требуемому шаблону, размер которых превышает 1 КБ. Затем этот список передается через headдля получения только первых 100 строк, а затем в xargsдля копирования файлов в соответствующий каталог.

Список имен файлов завершается NUL -на протяжении всего конвейера, поэтому он работает со всеми допустимыми именами файлов (, т. е. он не прерывается, если в именах файлов есть пробелы, символы табуляции, символы новой строки или другие необычные, но вполне допустимые символы.)

Для этого также требуется GNU-версия head(, которая является стандартной для Linux ), потому что она использует опцию -z(, также известную как--zero-terminated)для ввода с завершением NUL -. В частности, для этого требуется версия более поздняя, ​​чем 13 января 2016 года . Также требуется GNU cpдля параметра -t(, также известного как --target-directory), что позволяет указывать целевой каталог в качестве первого аргумента, а не последнего.

Если файлы необходимо отсортировать, то sort -zможно вставить между командами findи head-, например. find... -print0 | sort -z... | head -z.... Для этого также требуется версия GNU sort.

Это предполагает, что, как указано в редакции вашего вопроса, имена файлов имеют знак подчеркивания, за которым следует год, как последний элемент перед расширением .jpg.

Если год может появляться в любом месте имени файла, вам может понадобиться использовать-iname "*${year}*.jpg"(без подчеркивания и с секундой *между ${year}и .jpg), но следите за файлами, где восемь -цифровое число в начале похоже на 60420017, которое содержит 2001в качестве подстроки.

Это также предполагает, что все ваши файлы имеют (регистрозависимые -нечувствительные к регистру).jpgрасширения (, а не .jpeg, .jpe, .jfif, .gif, .pngи т. д. ). Если требуется несколько расширений имени файла, вместо -inameможно использовать параметр -iregex.

3
28.01.2020, 05:07

Теги

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