В моем родительском каталоге у меня есть 10 000 файлов, я хочу скопировать или переместить файлы в 4 подкаталога subdir1, subdir2, subdir3, subdir4 одинаково и, если возможно одновременно. К возможному для копирования определенного диапазона файлов от родительского каталога до подкаталогов т.е.
1-2500 файлов к subdir1
2500-5000 файлов к subdir2
5000-7500 файлов к subdir3
7500-10000 файлов к subdir4
Все они должны быть сделаны с помощью пакетного файла. Действительно ли это возможно? Выручите меня, если кто-либо знает.
Заранее спасибо.
Эти работы для произвольного числа файлов и могут иметь дело со странными именами файлов (те, которые содержат пробелы, новые строки, обратные косые черты или другую странность):
#!/usr/bin/env bash
## This will keep track of the number of files processed
num=0;
## This is used to choose the righht subdir
dir=1;
## The initial value of the target directory
target="subdir1"
for file in *; do
## Skip unless this is a file
if [ -f "$file" ]; then
## Create the target directory if it doesn't exist
[ -d "$target" ] || mkdir "$target"
## Move the current file
mv "$file" "$target"
## Change the target if we're at a multiple of 2500
if [[ $(( ++num % 2500 )) -eq 0 ]]; then
target="subdir"$((++dir));
fi
fi
done
можно также реализовать то же самое с помощью find
:
#!/usr/bin/env bash
## This will keep track of the number of files processed
num=0;
## This is used to choose the right subdir
dir=1;
## The initial value of the target directory
target="subdir1"
## Run your find, with -print0 to print NUL-separated values. This
## is needed for file names that contain newlines
find . -type f -print0 |
## The IFS= makes this deal with spaces, the -d '' sets the input delimiter
## to NUL so ti can work with -print0 and the -r makes it work with backslashes
while IFS= read -d '' -r file; do
## Create the target directory if it doesn't exist
[ -d "$target" ] || mkdir "$target"
## Move the current file
mv "$file" "$target"
## Change the target if we're at a multiple of 2500
if [[ $(( ++num % 2500 )) -eq 0 ]]; then
target="subdir"$((++dir));
fi
done
Сохраняют тот сценарий как ~/bin/batch_rename.sh
, делают его исполняемым файлом (chmod a+x ~/bin/batch_rename.sh
) и затем выполняют его из каталога, где файлы .
ПРИМЕЧАНИЯ
первый пример только найдет файлы в текущем каталоге. Для создания его рекурсивным добавьте эту строку к началу:
shopt -s globstar
Затем изменитесь for file in *
на for file in **/*
.
второй пример найдет все файлы в этом и любом подкаталоге. Это может или не может быть тем, что Вы хотите.
Этот bash
сценарий переместится, любое количество файлов, существующих в целевом каталоге, передало ему как аргумент, подпогружающийся их равномерно через любое число, переданное ему как аргумент целевых подкаталогов, названных subdir<N>
, уже создав целевые подкаталоги если не существующий; это должно быть помещено за пределами целевого каталога, который будет выполнен против избежать его перемещаемый во время выполнения.
Использование:
./script.sh <path_to_target_directory> <number_of_subdirectories>
*< path_to_target_directory> = соедините каналом к каталогу, содержащему файлы для подразделения; < number_of_subdirectories> = количество подкаталогов, на которые можно подразделить файлы
#!/bin/bash
for i in `seq 1 "${2}"`
do
mkdir -p \'"${1}"/subdir"${i}"\'
done
j=0
find \'"${1}"\' -maxdepth 1 -type f | while read -r filepath
do
N=$(( ${j} % ${2} + 1 ))
mv \'"${filepath}"\' \'"${1}/subdir${N}"\'
((${j}++))
done
Результаты для ./script.sh ~/testdir 4
:
Прежде:
~/testdir ├── 1 ├── 10 ├── 2 ├── 3 ├── 4 ├── 5 ├── 6 ├── 7 ├── 8 └── 9
После:
~/testdir ├── subdir1 │ ├── 1 │ ├── 2 │ └── 7 ├── subdir2 │ ├── 10 │ ├── 6 │ └── 8 ├── subdir3 │ ├── 3 │ └── 9 └── subdir4 ├── 4 └── 5
Если порядок не является проблемой, сценарием ниже:
chunk_1
, chunk_2
и т.д.)Обратите внимание на то, что:
#!/usr/bin/env python3
import os
import shutil
import sys
#--- if desired, change the sub dir's name body below
namebody = "chunk_"
#---
dr = sys.argv[1]; size = int(sys.argv[2]);
files = [f for f in os.listdir(dr) if os.path.isfile(dr+"/"+f)]
n = max(1, size)
chunks = [files[i:i + size] for i in range(0, len(files), size)]
for i, item in enumerate(chunks):
subfolder = os.path.join(dr, namebody+str(i+1))
if not os.path.exists(subfolder):
os.makedirs(subfolder)
for f in chunks[i]:
shutil.move(dr+"/"+f, subfolder+"/"+f)
reorganize.py
при желании можно изменить имя подкаталога "тело" (раздел имени без числа) в заголовке сценария, в:
namebody = "chunk_"
Выполните его с основным каталогом и размером блока как аргументы:
python3 /path/to/reorganize.py <main_directory> <chunk_size>
На основе моего старого сценария с некоторой модификацией (просто изменил значение N и имена переменной :):
##grouping each N files in separate directories
echo 1 > dircount;
find source -type f -name 'filterFileName' -print0 | sort -z --version-sort | \
xargs -0n2500 bash -c 'read TARGET <dircount; \
echo mkdir -p "subdir$TARGET"; \
echo mv -t "subdir$TARGET" "$@"; \
expr $TARGET + 1 >dircount' grouping
-print0
печатает имена файлов, разделенные NUL (\0
) символ. Это - самый безопасный способ передать имена файлов как вывод к другим командам.sort
с -z
ищет nul-разграниченный вход, и --version-sort
позволяет безопасно сортировать числа переменной длины, так, чтобы filename2.xyz прибыл прежде fileName3.xyzxargs
с -n2500
предел количество аргументов относился к каждой команде (в этом случае 2 500 аргументов). -0
для nul-разграниченного входа.Примечание: Не забывайте, что Вы запускаете скрипт в тестовом сценарии, так очиститесь echo
команда рядом со связанными строками к выполнению для запущения фактического скрипта.
groupFiles=0
TARGET=1
for file in `ls -v /path/to/source/filterFileName` ; do
mkdir -p "subdir$TARGET" && mv "$file" "subdir$TARGET"
[[ ++groupFiles -eq 2500 ]] && groupFiles=0 && ((TARGET++))
done
ls -v
команда сортирует файлы как естественный вид (версии) числа.ls
управляйте, не имеет ли имя файлов никакого пробела, новой строки, и т.д.mkdir -p "subdir$TARGET"
упаковывает каталог в ящики на основе TARGET
переменная.
mv "$file" "subdir$TARGET"
перемещает файл в каталог который TARGET
указывает.
groupFiles=0
обнулять, когда 2 500 файлов был перемещен ([[ ++groupFiles -eq 2500 ]]
) и инкремент к TARGET
значение.Обратите внимание на те изменения /path/to/source/
к Вашему фактическому исходному каталогу.
Если Вы не хотите анализировать ls
управляйте, чтобы должное имя файлов включая пробелы, новые строки и и т.д., вот было другой опцией сделать:
groupFiles=0
TARGET=1
find /path/to/source/ -type f -name 'filterFileName' -print0 | \
sort -z --version-sort | while IFS= read -d '' -r file; do \
mkdir -p "subdir$TARGET" && mv "$file" "subdir$TARGET" ;
[[ ++groupFiles-eq 7 ]] && groupFiles=0 && ((TARGET++));
done