在我的父目录中,我有 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_1
等chunk_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)
如何使用
- 将脚本复制到一个空文件中,另存为
reorganize.py
如果需要,您可以在脚本的头部更改子目录的名称“body”(没有数字的名称部分),如下所示:
namebody = "chunk_"
使用主目录和块大小作为参数运行它:
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
-print0
打印由 NUL (\0
) 字符分隔的文件名。这是将文件名作为输出传递给其他命令的最安全方法。sort
with-z
查找以空字符分隔的输入,并--version-sort
允许安全地对可变长度的数字进行排序,以便 filename2.xyz 位于 fileName3.xyz 之前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