LINUX.ORG.RU

Как разбить по разным каталогам содержимое одного в 8000 файлов?

 , ,


2

2

Есть каталог с более чем 8000 файлов. Для ускорения работы с ним, нужно разбить находящиеся в нём файлы на группы по какому-либо признаку. 1) вариант создать 8 подкаталогов, и переместить в каждый по 1000 файлов. 2) Поскольку файлы добавлялись годами, создать папки с номерами годов, и в каждый поместить созданные в нём файлы.

Вопрос, как такое лучше всего сделать?

Приходит на ум find, но только для варианта 2).

find . -mindepth 1 -newermt '2011-01-01 00:00' ! -newermt 
'2012-01-01 00:00' -ls

Вот только выдача по -ls кривая. Вместо русских имён файлов юникоды: /\320\243\320\261\320\270\321\202\321\214\
Выдача просто по ls корректная.
почему вывод ls через find кривой и как это исправить? man пишет, что русские буквы ему UNUSUAL FILENAMES, поэтому по дефолту выводит так. Как отучить его от этого, пока не дочитал.

★★★

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

Ответ на: комментарий от superuser

Патч нумбер 1

--- /tmp/iliketomoveit.old
+++ /tmp/iliketomoveit
@@ -16,12 +16,12 @@
 done
 }
 
-if [ $# -eq 0 ]; then
+if [ $# -ne 1 ]; then
     USAGE;
     exit 0
 fi
 
-echo "Source dir.: $1"
+echo "Source dir.: '$1'"
 echo "Press 'y' for continue..."
 read -s -n 1 key

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

На tcl

echo 'foreach f [glob *] {file mkdir [set y [clock format [file mtime $f] -format %Y]];file rename $f $y}' | tclsh
gorky ★★
()
Ответ на: комментарий от superuser

Патч нумбер 1

Зачем после USAGE точка с запятой? Кстати, при количестве аргументов 0 обычно, если возможно, рассматривается как вызов с сообщением о том, как надо вызывать, а вот вызов с ошибочными аргументами надо выводить usage() в stderr и ненулевым кодом exit (обычно теперь принято для usage — 2).

Но вообще тут в топике уже много сказано, что такой скрипт имеет проблемы с именами, начинающимися с пробела или переводом строки.

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

такой скрипт имеет проблемы с именами, начинающимися с пробела

Проверял на файлах и директориях начинающихся с пробела - работает правильно, проблем не заметил.

или переводом строки

как такое можно сотворить?
Патчи принимаются!

superuser ★★★★★
()
Последнее исправление: superuser (всего исправлений: 1)
Ответ на: комментарий от legolegs
user@pc:~$ iliketomoveit '/tmp/ АБС 111 '
Source dir.: '/tmp/ АБС 111 '
Press 'y' for continue...
[2020] [/tmp/ АБС 111 / ну вот такой "$%& файлик как пойдёт?]
[2020] [/tmp/ АБС 111 / ГДЕ 111 / ну вот такой "$%& файлик как пойдёт?]
[2020] [/tmp/ АБС 111 / ГДЕ 222 / ну вот такой "$%& файлик как пойдёт?]

user@pc:~$ cd /tmp
user@pc:/tmp$ iliketomoveit ' АБС 111 '
Source dir.: ' АБС 111 '
Press 'y' for continue...
[2020] [АБС 111 / ну вот такой "$%& файлик как пойдёт?]
cp: не удалось выполнить stat для 'АБС 111 / ну вот такой "$%& файлик как пойдёт?': Нет такого файла или каталога
[2020] [АБС 111 / ГДЕ 111 / ну вот такой "$%& файлик как пойдёт?]
cp: не удалось выполнить stat для 'АБС 111 / ГДЕ 111 / ну вот такой "$%& файлик как пойдёт?': Нет такого файла или каталога
[2020] [АБС 111 / ГДЕ 222 / ну вот такой "$%& файлик как пойдёт?]
cp: не удалось выполнить stat для 'АБС 111 / ГДЕ 222 / ну вот такой "$%& файлик как пойдёт?': Нет такого файла или каталога

user@pc:/tmp$ iliketomoveit './ АБС 111 '
Source dir.: './ АБС 111 '
Press 'y' for continue...
[2020] [./ АБС 111 / ну вот такой "$%& файлик как пойдёт?]
[2020] [./ АБС 111 / ГДЕ 111 / ну вот такой "$%& файлик как пойдёт?]
[2020] [./ АБС 111 / ГДЕ 222 / ну вот такой "$%& файлик как пойдёт?]

Смотрите внимательно выхлоп! А ведь где-то рептилоид собака порылась!

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

Проверял на файлах и директориях начинающихся с пробела - работает правильно

Нет. Когда делается read v1 v2, то все пробелы проигнорируются между словами.

Смотрите внимательно выхлоп!

Ваша точка превращает первый пробел в точку. Но не чинит перевод строки в имени и последние пробелы.

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

Ваша точка превращает первый пробел в точку.

Нифига не понял, но очень интересно.

Но не чинит перевод строки в имени и последние пробелы.

С пробелами и в конце и в начале всё замечательно. Я проверял!

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

Для тех кто не справляется с пробелами пр. символами доступны null terminated (h00, 0x00) строки. Тот же find … -print0 , xargs -0 …, sed -z …, grep -Z … почти весь утиль может работать со строками в стиле С

И никаких проблем

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

С пробелами и в конце и в начале всё замечательно. Я проверял!

Я не знаю, что вы там проверяли, но даже логически это никак не вяжется. Впрочем, вот можете проверить проще:

$ echo "2020  b " | { read -r r1 r2; echo "'$r1' '$r2'"; }
'2020' 'b'

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

Для тех кто не справляется с пробелами пр. символами доступны null terminated (h00, 0x00) строки.

Какой сюрприз... Ну то есть этот коммент прочитать и осмыслить никак было не возможно. Ага.

почти весь утиль может работать со строками

Увы. Вы и перечислили почти весь набор утилит, которое это понимает. При том, что так как раз для скриптов эта необходимость возникает имеено из-за того, что надо передать внешним программам. Внутри скриптов этой проблемы нет.

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

Упс точно. Что-то пошло не так. Последние пробелы и правдв теряются. Как проглядел непойму, специально же присматривался.

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

И в bash официально нельзя никак сохранить \0 в переменную/heredoc/herestring.

Да, но мы же про обработку имён файлов, а не про бинарные данные всего диапазона байт. Потому for file in *; работает лет 50, а вот как передать во вне с разделителми, так вдруг выясняется, что утилей с null terminated до сих пор по пальцам пересчитать, да и то зачастую GNU-расширение только.

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

Последние пробелы и правдв теряются.

Да блин. И первые тоже! И если с последними как раз всё не так однозначно с точки зрения логики, то вот с первыми как раз всё согласно логике. То что у вас можно в скрипте засунуть первым символом точку — это дурацкий трюк, как и любой трюк он работает только в узком смысле, а не вообще.

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

Ты можешь оперировать с файлами не по именам, а по inode number через find -inum и ls -i, например, если там слишком хитрые имена.

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

А можно как-то открыть файл на чтение/запись по inode? Про перемещение/переименование по inode не спрашиваю - это бессмысленный вопрос.

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

for file in *; do command "$file" или find -exec ... или find -print0 |. Самые пуленепробиваемые и самые безболезненные варианты.

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

Ну не прямо открыть по inode, но указать inode из выхлопа ls -i в конструкции типа find -inum -exec cat {} \; например

Для ситуаций, когда файл есть, но имя ввести невозможно - пару раз спасало

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

find -exec ... Самые пуленепробиваемые и самые безболезненные варианты.

Ну нет же. ТСу повезло, что ему от внешней программы нужно только одно число. И потому его устроило собирать как rez=$(find ... | convert) А если что-то больше? Через временный файл?

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

пару раз спасало

Если уж речь о спасении, то стоит помнить, что после ls -i, паресенье этого и find-ом может пройти для железа охрененное время и вы получите не спасение, а сделаете только хуже.

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

А если что-то больше?

А в чём проблема? Обычный map-reduce. И map и reduce можно реализовать как удобно, от вызова пустяковой утилиты до отдельного файла скрипта.

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

А в чём проблема?

Ну много же уже говорили с тобой. Внешний скрипт через sh -c если не однострочник ну ни как не тянет на «безболезненный», а натуральный ад. А вот работа с внешними прогами построчно в цикле - основное предназначение sh, оно именно для этого и создано! А вот ваш любимый awk с работой с внешними программами и null-terminated вот совсем никак. Почувствуйте разницу.

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

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

Читать кучи форумного говна? Нет, я не такой.

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

Нет, я не такой.

Отож. Тот то коммент был решением проблем предыдущего коммента, а ваш — бесполезным высером, засоряющий форум тем, что уже как двое суток всё до этого было объяснено.

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

Использовал твой пример. Так ошибок не будет?

#!/bin/bash

USAGE() {
echo "Use: $(basename $0) path-to-directory";
return 0
}

DO() {
(find "${1}" -type f -printf '%TY\0%p\0'; printf '\0\0') | 
while IFS= read -r -d '' year; IFS= read -r -d '' fname; do
	[[ -z $year ]] && echo "DONE." && break
	[[ $fname = . ]] && continue
        printf '[%s] [%s]\n' "$year" "$fname"
	td="${1}_${year}/"
	mkdir -p "${td}"
	#cp --backup=numbered --preserve "${fname}" "${td}"
	mv --backup=numbered "${fname}" "${td}"
done;
}

if [ $# -ne 1 ]; then
    USAGE
    exit 2
fi

echo "Source dir.: '$1'"
read -n1 -p "Press 'y' for continue... : " key
echo ""

case $key in
[y,Y])
DO "${1}"
exit 0
;;
*) 
echo "Abort."
exit 1
esac

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

Выглядит надёжно. Подтверждение запуска и DONE не соответсвуют unix-way, но это стилистическое.

Сломается и насрёт полную консоль ошибок cp/mv, если не будет прав на mkdir, например если мы сделаем от юзера скрипт.sh /var/ftp/pub/. Такое сработать и не должно, разумеется, но лучше, когда программа не выдаёт километровый список ошибок, а только первую, самую важную.

Я обычно начинаю более-менее полноценные скрипты с set -euo pipefail, где -e заставит скрипт остановиться после первой же несработавшей строки. Но это тут не обязательно. Обработка ошибок - это вообще сложно и иногда лучше не увлекаться.

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

Подтверждение запуска ... не соответсвуют unix-way

это для того чтобы случайно не перемувили %BIGDATADIR% а то ойойой.

но лучше, когда программа не выдаёт километровый список ошибок

да, надо доработать

В общем я 20Gb фоточек рассортировал по годам удачно.

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

Использовал твой пример. Так ошибок не будет?

Вы его переделали и получили не сколько ошибки, сколько лишнего масло-масленного от непонимания. legolegs, неужели не заметил?

Итак. Во-первых, первые скобочки ( ) тут не нужны, лишний процесс, тут напрашивается как минимум { }, но и это не надо, см. ниже. Во-вторых, у меня был while true, а вы поставили while read. Следовательно printf '\0\0' уже не нужен, у вас и так оно определелит по EOF, (правда двойным read из EOF). В-третьих, у меня был find без -type f, у вас он есть, потому '.' никак в выводе find-а не может быть и проверка лишняя. Более того, если бы -type f не было, а в «$1» у вас был бы не '.', то была бы не точка, а именно этот $1

Ну и стилистически, Abort с exit 1 - лишнее, надо просто молча завершаться с правильным кодом, это не ошибка, а хороший результат диалога с человеком.

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

DONE не соответсвуют unix-way,

Ну всякие -v -s иногда так многословны, что иногда бесят :) В принципе правильнее было б именно ключ -s (статистика) с подсчётом этого done.

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

бред

Помолчали б, за умного сошли.

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

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

Какие удаления и починки?

Что ж ты такой тупой. «Удаления» — одно из действий при работы системы. «Починки» — от поднятой проблемы «спасения».

Болеешь?

Удивительно, как же вас корёжит, когда умишка не хватает распарсить что-то сложнее привычного тут тупого трёпа. Но раз уж так упорно добивался, то поздравляю, можете не стараться, ставлю в игнор.

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

Вот ты придурок с завышенным ЧСВ. Игнорь, мне только проще будет не видеть дебилов.

Работать с файлами параллельно с починкой фс может только дебил как ты.

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

Углядеть все недочёты мог только спец. Спасибо за замечания.

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