如何将特定范围的文件从一个目录移动到另一个目录

如何将特定范围的文件从一个目录移动到另一个目录

在我的父目录中,我有 10000 个文件,我想将这些文件平均复制或移动到 4 个子目录 subdir1、subdir2、subdir3、subdir4,如果可能的话同时复制或移动到。是否可以将一定范围的文件从父目录复制到子目录,即

将 1-2500 个文件复制到 subdir1 将
2500-5000 个文件复制到 subdir2
将 5000-7500 个文件复制到 subdir3
将 7500-10000 个文件复制到 subdir4

所有这些都应该使用批处理文件完成。 可以吗? 如果有人知道,请帮助我。

提前致谢。

答案1

这个适用于任意数量的文件,并可以处理奇怪的文件名(包含空格,换行符,反斜杠或其他奇怪的东西):

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

如果顺序不是问题,则脚本如下:

  • 将文件分割成(任意)块
  • 为每个块创建子目录(chunk_1chunk_2
  • 将相应文件移动到子目录中

注意:

  • 如果订单一个问题,脚本需要进行微调,但请在问题中包含顺序规则。
  • 该脚本不会“介意”带有空格等的文件(-names)。甚至子目录的名称“body”也可能包含空格。

剧本

#!/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. 如果需要,您可以在脚本的头部更改子目录的名称“body”(没有数字的名称部分),如下所示:

    namebody = "chunk_"
    
  3. 使用主目录和块大小作为参数运行它:

    python3 /path/to/reorganize.py <main_directory> <chunk_size>
    

答案3

基于我的旧剧本进行了一些修改(仅改变了 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. sortwith-z查找以空字符分隔的输入,并--version-sort允许安全地对可变长度的数字进行排序,以便 filename2.xyz 位于 fileName3.xyz 之前
  3. xargs限制-n2500应用于每个命令的参数数量(在本例中为 2500 个参数)。 用于-0以空字符分隔的输入。

注意:不要忘记您正在测试用例中运行脚本,因此请清除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当已移动 2500 个文件时,将重置为零( [[ ++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

答案4

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

前:

〜/测试目录
── 1
── 10
│ │ 2
│ ── 3
│── 4
│ 5
│ │ 6
│ │ 7
..........8
└── 9

后:

〜/测试目录
│ │ 子目录1
│ │── 1
│ │── 2
│ └── 7
│ │ 子目录2
│ │── 10
│ │── 6
│ └── 8
│ │ subdir3
│ │── 3
│ └── 9
└── subdir4
    │── 4
    └── 5

相关内容