как переместить определенный диапазон файлов от одного каталога до другого

В моем родительском каталоге у меня есть 10 000 файлов, я хочу скопировать или переместить файлы в 4 подкаталога subdir1, subdir2, subdir3, subdir4 одинаково и, если возможно одновременно. К возможному для копирования определенного диапазона файлов от родительского каталога до подкаталогов т.е.

1-2500 файлов к subdir1
2500-5000 файлов к subdir2
5000-7500 файлов к subdir3
7500-10000 файлов к subdir4

Все они должны быть сделаны с помощью пакетного файла. Действительно ли это возможно? Выручите меня, если кто-либо знает.

Заранее спасибо.

3
задан 27 April 2015 в 14:18

4 ответа

Эти работы для произвольного числа файлов и могут иметь дело со странными именами файлов (те, которые содержат пробелы, новые строки, обратные косые черты или другую странность):

#!/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 **/*.

  • второй пример найдет все файлы в этом и любом подкаталоге. Это может или не может быть тем, что Вы хотите.

2
ответ дан 1 December 2019 в 16:28

Этот 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
0
ответ дан 1 December 2019 в 16:28

Если порядок не является проблемой, сценарием ниже:

  • разделяет файлы на (произвольные) блоки
  • создает подкаталоги на блок (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)

Как использовать

  1. Скопируйте сценарий в пустой файл, сохраните его как reorganize.py
  2. при желании можно изменить имя подкаталога "тело" (раздел имени без числа) в заголовке сценария, в:

    namebody = "chunk_"
    
  3. Выполните его с основным каталогом и размером блока как аргументы:

    python3 /path/to/reorganize.py <main_directory> <chunk_size>
    
1
ответ дан 1 December 2019 в 16:28

На основе моего старого сценария с некоторой модификацией (просто изменил значение N и имена переменной :):

Группировка каждого файлы 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
  1. -print0 печатает имена файлов, разделенные NUL (\0) символ. Это - самый безопасный способ передать имена файлов как вывод к другим командам.
  2. sort с -z ищет nul-разграниченный вход, и --version-sort позволяет безопасно сортировать числа переменной длины, так, чтобы filename2.xyz прибыл прежде fileName3.xyz
  3. xargs с -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
0
ответ дан 1 December 2019 в 16:28

Другие вопросы по тегам:

Похожие вопросы: