LINUX.ORG.RU

Скрипт разнести все файлы в директории по нужному количеству в новые директории

 ,


0

1

Помогите создать скрипт. В директории много-сот файлов. Нужно автоматически создать нужное количество директорий, например 01,02,03 ... и т.д. и в каждую директорию переместить из общей например по 25 файлов. Желательно, что бы скрипт был внешним, то есть лежал в другом месте и к нему обращаться на предмет выделенных файлов.
UPD. Важное дополнение. Да, эта просьба по сути - «сделайте за меня». За понимание спасибо.

★★

Последнее исправление: abbat81 (всего исправлений: 2)

mv
mkdir
for

Миксуешь эти команды до приемлемого результата, по необходимости поглядывая в гугл.

SuoiCat
()
Ответ на: комментарий от abbat81

Если ты передаешь количество файлов на директорию в аргументах, то тебе нужно посчитать количество файлов в текущей директории и разделить на переданное число N. Так ты узнаешь, сколько новых директорий создать (mkdir). Потом итерируешься по файлам (for), перенося их в новосозданные директории (mv).

SuoiCat
()

Держи:

DIRN=0
FILEN=25
for file in largedir/*; do
    if [ $FILEN == 25 ]; then
        FILEN=0
        ((++DIRN))
        DIR=$(printf %03d $DIRN)
        mkdir "$DIR"
    fi
    mv -t "$DIR" "$file"
    ((++FILEN))
done

legolegs ★★★★★
()
Ответ на: комментарий от legolegs

Вот альтернативный вариант,если файлов ОЧЕНЬ много (работает быстрее):

find largedir/ -type f -print0 |
    xargs -0n25 bash -c '
        DIR=$(printf %03d $(ls | wc -l))
        mkdir "$DIR" &&
        mv -t "$DIR" -- "$@"' -

(я был бы не я, если бы не сделал вариант на пайпах)

legolegs ★★★★★
()
Ответ на: комментарий от legolegs

Нуууу не знаю, почему это у вас должно работать быстрее.

Вот вам для произвольного количества, чтобы не ошибиться в знаках у printf:

#!/bin/bash
MAX_FILE_IN_DIR=25

files=(largedir/*)
nfiles=${#files[@]}
make_dir_and_move() {
        printf -v DIR "%0${#nfiles}d" $((++DIRN))
        mkdir $DIR
        mv "${out[@]}" $DIR
        out=()
}
for i in ${!files[@]} ; do
  [[ ${#out[@]} -eq $MAX_FILE_IN_DIR ]] && make_dir_and_move
  out+=("${files[i]}")
done
[[ ${#out[@]} -ne 0 ]] && make_dir_and_move
У скрипта есть одна плюха, но оставим в качестве домашнего задания.

vodz ★★★★★
()
Последнее исправление: vodz (всего исправлений: 2)
Ответ на: комментарий от legolegs

Заменил «$file» на «$1» иначе только создавало папку 001. Выделив все 52 файла, переносит все 52 файла в папку 001

abbat81 ★★
() автор топика
Последнее исправление: abbat81 (всего исправлений: 1)
Ответ на: комментарий от vodz

при обращении к скрипту создало папку 1 и все

abbat81 ★★
() автор топика

Да, эта просьба по сути - «сделайте за меня»

В job.

aedeph_ ★★
()
Ответ на: комментарий от vodz

Нуууу не знаю, почему это у вас должно работать быстрее.

Быстрее, чем если по одному вызову mv на файл, разумеется.

На наборе из 80000 файлов вариант с xargs сравним по скорости с вашим с массивами, но это из-за ls|wc. C mktemp -d xargs вырывается вперёд вдвое, а в многопоточном режиме творит чудеса даже на шпинделе. А вот с количествами порядка 1000..5000 ваш вариант чутка шустрее.

legolegs ★★★★★
()
Ответ на: комментарий от legolegs

Ну вот это «ls|wc» как раз и смущает. Даже не по скорости, а по какой-то грязности, если угодно.. Вначале у нас find -print0, все дела, а потом ls...

vodz ★★★★★
()
Последнее исправление: vodz (всего исправлений: 1)
Ответ на: комментарий от legolegs

/home/user/move2folder.sh

#!/bin/bash
DIRN=0
FILEN=25
for file in largedir/*; do
    if [ $FILEN == 25 ]; then
        FILEN=0
        ((++DIRN))
        DIR=$(printf %03d $DIRN)
        mkdir "$DIR"
    fi
    mv -t "$DIR" "$file"
    ((++FILEN))
done

/home/user/.local/share/applications/move2folder.desktop
[Desktop Entry]
Type=Application
Name=move2folder

Exec=/home/user/move2folder.sh
Terminal=false
Encoding=UTF-8
Выделяю 50 файлов, правой - move2folder и все, как я выше описал. Что не так?

abbat81 ★★
() автор топика
Ответ на: комментарий от anonymous

класс,

Да ну нафиг. Оно у него не рабочее. Имя каталога ровно одно: количество файлов в текущей директории. Хрень какая-то.

куда лучше портянки иероглифов у водза!

Пф. Не знать иероглифы — не беда. Мало ли у кого есть какие другие интересные задачи кроме знания bash. Но вот высказывать оценочные суждения при этом — выставлять себя идиотом.

забрал себе

Вот вот. А проверять и не надо, ага.

vodz ★★★★★
()
Последнее исправление: vodz (всего исправлений: 1)
Ответ на: комментарий от abbat81

Что не так?

Всё не так. Это другая задача. У вас про это ничего не написано было. Тут вам не виндоза, у меня вообще на сотни серверов нет никаких десктопов, кроме рабочей машины. Теперь она должна формулироваться у вас типа: хочу написать скрипт для KDE или чего у вас там и так далее...

vodz ★★★★★
()
Ответ на: комментарий от abbat81

При чем тут вообще DE?

Вот именно, вот себе и задавайте вопрос, причём тут.

vodz ★★★★★
()
Ответ на: комментарий от vodz

Я то иероглифы эти прекрасно понимаю, но мне от этого не легче. Баш точно не самый читаемый язык, писать на нём что-то и поддерживать это потом совсем не хочется, хуже только cmd.exe. Да и называть внезапно собеседника идиотом совсем не круто. Хотя я ждал этого :)

anonymous
()
Ответ на: комментарий от anonymous

Я то иероглифы эти прекрасно понимаю, но мне от этого не легче.

А что же вы удалили первую часть комментария, где было показано, что нифига вы не понимаете, тем более прекрасно?

Хотя я ждал этого :)

Мазохист чтоле? Нарываться, получить и радостно трубить, что «ждал этого». Тьфу.

vodz ★★★★★
()
Ответ на: комментарий от legolegs

Кстати, насчёт (ls | wc -l), с одной стороны это хорошо, что можно добавлять каталоги, с другой, принципиально получится лажа если вызывать в рабочей директории с файлами для move. Так что если заменить на find -type d, то будет и более-менее рабочее и оригинально. С последним каталогом только каждой итерации только будет изъян, ну да ладна :)

vodz ★★★★★
()
Ответ на: комментарий от vodz

Да дурацкое решение, как ни крути. И сложность неконстантная, и нумерация сбивается и io лишний. ls ещё и stat делает и сортирует.

Я придумал решение получше, со вторым потоком ввода, но мне сегодня лень его оформлять.

legolegs ★★★★★
()
Ответ на: комментарий от legolegs

Лень - дело святое, но как нибудь сформулируй его сюда. Ты уже как-то сформулировал, я каждый день пользуюсь «parallel script.sh ::: %F»., Спасибо. Создать директорию рядом с файлом (комментарий)

Хотя тут ненужно паралельного потока, потому, что один поток омжет обогнать дргуой и напихают разное количество файлов. Теоретически. Тем не менее, это не обработка файлов, производительности не требуется.

abbat81 ★★
() автор топика
Последнее исправление: abbat81 (всего исправлений: 3)
Ответ на: комментарий от abbat81

без производительности вот этого должно быть достаточно

#!/bin/bash
DIRN=0
FILEN=25
for file in "$@"; do
    if [ $FILEN == 25 ]; then
        FILEN=0
        ((++DIRN))
        DIR=$(printf %03d $DIRN)
        mkdir "$DIR"
    fi
    mv -t "$DIR" "$file"
    ((++FILEN))
done
[Desktop Entry]
Type=Application
Name=move2folder

Exec=/home/user/move2folder.sh %F
Terminal=false
Encoding=UTF-8
legolegs ★★★★★
()
Ответ на: комментарий от legolegs

Все работает. Большая благодарность!

abbat81 ★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.