Как организовать изображения в каталоге в классы, зависящие от значений столбцов данных? - PullRequest
0 голосов
/ 01 марта 2019

У меня есть каталог изображений из этой компаньоны .Изображения с одним и тем же животным имеют одинаковый префикс в названии, за которым следует -{num}, где num - числовое изображение этого конкретного животного.

Итак:

abc-1.jpg
abc-2.jpg
def-1.jpg
...
abg-1.jpg
abg-2.jpg
abg-3.jpg
poc-1.jpg
qrs-1.jpg

Итак, как вы можете видеть, может быть различное количество изображений каждого.

Тогда у меня есть фрейм данных (или .csv), который имеет1 столбец, который является префиксом имени файла каждого животного, и другой столбец, который является классом [0,1,2,3,4,5], и последний столбец, который содержит количество изображений для каждого животного

ОБНОВЛЕНИЕ: предположим, что мы ужеиметь количество изображений каждого животного

animal    class     num_images
abc        0            2
def        0            1
abg        2            3
poc        1            1
qrs        4            1

Я хочу организовать изображения в каталогах: dir0, dir1, dir2, dir3, dir4, dir5, основываясь на классе, которому соответствует изображение.

Вот одинкак я себе представляю, выполняя эту задачу: (определенно не лучшим образом) мне удалось получить команду bash, которая организует изображения в каталоги на основе префикса: for file in *.jpg; do mkdir -p -- "${file%%-*}" && mv -- "$file" "${file%%-*}"; done

Затем каким-то образом просматривая каждый префикс животных ви добавьте соответствующие {num} и поместите их в каталог с именем: dir + {class}

Ответы [ 3 ]

0 голосов
/ 01 марта 2019

Основная команда

Этот ответ использует тот же подход, что и Ответ Индера , но внутри одной команды awk, которая может быть быстрее.Не то чтобы это имело значение в этом случае ... Здесь мы предполагаем, что файл, указанный в вашем примере в качестве входных данных, см. Следующий раздел для альтернативных форматов ввода.

awk 'NR>1 { system("mkdir -p dir"$2"; mv "$1"-* dir"$2) }' dataframe.csv

В вашем примере это выполняет следующее bash команды:

mkdir -p dir0
mv abc-* dir0
mkdir -p dir0
mv def-* dir0
mkdir -p dir2
mv abg-* dir2
mkdir -p dir1
mv poc-* dir1
mkdir -p dir4
mv qrs-* dir4

Параметр -p mkdir не вызовет ошибку, если каталог уже существует.С помощью mv abc-* dir0 мы перемещаем все файлы, начиная с abc-, в каталог dir0.

Использование вашего фактического формата ввода

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

animal    class
abc        0
def        0
abg        2
...

, но ваш реальный файл выглядит как настоящий csv со столбцами, разделенными запятыми.Кроме того, файл, похоже, имеет окончания строк в Windows (\r\n вместо \n).

animal,class\r
abc,0\r
def,0\r
abg,2\r
...

Этот формат можно использовать, адаптируя специальные переменные awk FS (для поляразделитель) и RS (для разделителя записей):

awk -F, -v RS='\r?\n' 'NR>1 { system("mkdir -p dir"$2"; mv "$1"-* dir"$2) }' dataframe.csv
0 голосов
/ 01 марта 2019

Часто, когда я пишу умеренно сложный сценарий - или сценарий, который должен повторяться правильно большое количество раз - я не пишу сценарий, который выполняет работу, я пишу сценарий, который выводитпоследовательность команд, которые сделают работу.Таким образом, я могу потратить некоторое время, чтобы просмотреть вывод скрипта и определить, выглядит ли последовательность команд, сгенерированная им, разумной.Так как это всего лишь команды оболочки, я также могу включить комментарии в вывод скрипта, чтобы «показать мою работу» и подтвердить, что действия, выполняемые скриптом, основаны на звуковой логике.

Решение Индера действительно умное, чтоПодстановочный знак будет достаточно.Пока он писал это, я писал:

Пусть каталоги dirN уже созданы, таблица классов находится в файле class, а список файлов, которые нужно переместить в файл files.

#!/usr/bin/env bash

# read in the class table:

eval $(
tail +2 classes |\
while read PREF CLASS
do
        echo X$PREF=$CLASS\;
done
)

# now iterate through the filenames:

while read FILE
do
        GROUP=${FILE%%-*}
        CLASS="X${GROUP}"
        printf '# file "%s" is group "%s", which is class "%s"\n' "$FILE" "$GROUP" "${!CLASS}"
        printf 'mv -vi "%s" "dir%s"\n' "$FILE" "${!CLASS}"
done < files

Вывод этого скрипта:

$ ./foo.sh
# file "abc-1.jpg" is group "abc", which is class "0"
mv -vi "abc-1.jpg" "dir0"
# file "abc-2.jpg" is group "abc", which is class "0"
mv -vi "abc-2.jpg" "dir0"
# file "def-1.jpg" is group "def", which is class "0"
mv -vi "def-1.jpg" "dir0"
# file "abg-1.jpg" is group "abg", which is class "2"
mv -vi "abg-1.jpg" "dir2"
# file "abg-2.jpg" is group "abg", which is class "2"
mv -vi "abg-2.jpg" "dir2"
# file "abg-3.jpg" is group "abg", which is class "2"
mv -vi "abg-3.jpg" "dir2"
# file "poc-1.jpg" is group "poc", which is class "1"
mv -vi "poc-1.jpg" "dir1"
# file "qrs-1.jpg" is group "qrs", which is class "4"
mv -vi "qrs-1.jpg" "dir4"

Если эти команды выглядят нормально, затем снова запустите скрипт и направьте вывод в bash:

$ ./foo.sh  | bash
abc-1.jpg -> dir0/abc-1.jpg
abc-2.jpg -> dir0/abc-2.jpg
def-1.jpg -> dir0/def-1.jpg
abg-1.jpg -> dir2/abg-1.jpg
abg-2.jpg -> dir2/abg-2.jpg
abg-3.jpg -> dir2/abg-3.jpg
poc-1.jpg -> dir1/poc-1.jpg
qrs-1.jpg -> dir4/qrs-1.jpg

Создание «мета-сценария» таким способом позволяет проверять свою работу перед выполнением, возможно, не совсем корректного действия тысячи раз.Однако, это может быть непрактичным в тех случаях, когда существует не тысячи, а миллионы или миллиарды итераций.Тем не менее, если кто-то использует эту технику на небольшой подвыборке набора данных мамонта, это может быть очень полезным методом для отладки логики вашего скрипта без каких-либо недостатков или ошибок в вашем скрипте.Просто внимательно прочитайте вывод сценария, прежде чем направлять его в оболочку live bash.

0 голосов
/ 01 марта 2019

Это должно сработать, с ценными данными из @Socowi:

while read -r f1 f2 #store values of each row for first column and second
do

    mkdir "dir${f2}" #makes directory with the name
    mv ${f1}.* "dir${f2}/" #moves all the files with the class name to that directory 

done < <(tail +2 file.csv) #reads file line by line except first

PS file.csv - это файл, содержащий классы, их имена и т. Д., Количество файлов на самом деле не имеет значения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...