Я хочу распараллелить разбиение множества каталогов на подкаталоги с помощью parallel
или с использованием другого инструмента или метода.
Например, у меня есть 1 000 000 каталогов с контентом, но это слишком много для одного каталога, поэтому я хочу создать 10 каталогов в главном каталоге и переместить в каждый из них 100 000 исходных каталогов. Я также хочу использовать сортировку по дате. Я уже спрашиваланалогичный вопрос здесь, но это не дубликат, потому что я попробовал новые команды, получил новые результаты и теперь переформулировал вопрос.
Итак, я уже попробовал это.
ls -tr|parallel -n100000 mkdir "dir_{#}"\;mv {} "dir_{#}"
и это
ls -tr | parallel -j10 -n100000 --no-notice -k 'mkdir -p dir_{#}; mv {} -t dir_{#}'
команды, но он перемещает только ~10 000 в один подкаталог (иногда ~6200, иногда ~12 500) и создает слишком много подкаталогов - иногда в 10 раз больше, чем мне нужно.
Я также пытался использовать это:
ls -dtr * | parallel -j10 -n100000 --no-notice -k 'mkdir -p dir_{#}; mv {} -t dir_{#}'
но это дало bash: /bin/ls: Argument list too long
.
Конечно, мне не нужно ровно 100 000 каталогов в каждом подкаталоге, это может быть 101 000 или 98 500 каталогов, это должно быть число в диапазоне 100 000.
Как я могу выполнить эту задачу параллельно или с помощью parallel
?
решение1
Проблема в том, что существует верхний предел байтов, которые может занять командная строка после расширения оболочки, этот предел зависит от предела системы
getconf ARG_MAX
таким образом, количество аргументов будет mv {}
меняться в зависимости от длины имени входного файла всякий раз, когда вы достигаете максимального предела.
Решение обойти это ограничение, не отказываясь от использования параллелизма, состоит в том, чтобы разбить задачу на два этапа.
ls -tr | parallel -N 100000 --pipe -k "mkdir dir_{#}; parallel -X mv -t dir_{#}"
Объяснение
На первом этапе используется возможность
--pipe
разбить stdin на определенное количествоменьшие стандартные вводы, каждый из которых содержит n строк, как указано в параметре-N
. Вы можете наблюдать эффект, используя этот примерseq 1000000 | parallel -N 100000 --pipe wc -l
что дает точное разделение на отметке 100000
100000 100000 100000 ...
На втором этапе внутренние параллели принимаютменьшие стандартные вводыв качестве нового стандартного ввода для выполнения заданий
-X
опция вставляет столько аргументов, сколько позволяет длина командной строкиmkdir dir_{#}; parallel -X mv -t dir_{#}
решение2
Эта проблема касается тяжелого ввода-вывода. Сомневаюсь, что это parallel
действительно полезно в данной ситуации.
В любом случае я предлагаю вам рассмотреть «традиционный» подход:
mkdir dir_{1..10}
ls -tr | nl | \
awk '$2 !~ /^dir_/ {i=1+int($1/100000); print $2 | "xargs mv -t dir_"i}'
где
ls -tr | nl
сортирует каталоги по дате и добавляет вспомогательный номер каталога$2 !~ /^dir_/
используется для пропуска только что созданных папок.i=1+int($1/100000)
вычисляет номер папки на основе dir-numberprint $2 | "xargs mv -t dir_"i
движется без распространения процесса
Если возможно, сравните также соответствующее время: time ....
(и поделитесь с нами результатами ☺)