将文件重新分配到多个最大大小的子目录中
Redistribute files into multiple sub-directories with maximum size
我有一个很大的目录 files_pdf
,其中包含 110 000 个 pdf 文档。这些文档中的每一个都有不同的文件大小。
我想将所有这些文档重新分发到一组子目录中,以便所有子目录的总累积大小大约 相同。我不想将文件拆分成多个部分。
我试过:
split -b 4000k myfile segment
但在某些情况下它会破坏我的 PDF。
基于 bin-packing First-fit 算法的解决方案可能如下所示。
创建名为 bin_packing.awk
的文件:
function first_fit(v, file) {
# find first bin that can accomodate the volume
for (i=1; i<=n; ++i) {
if (b[i] > v) {
b[i] -= v
bc[i]++
cmd="mv "file" subdir_" i
print cmd
# system(cmd)
return
}
}
# no bin found, create new bin
if (i > n) {
b[++n] = c - v
bc[n]++
cmd="mkdir subdir_"n
print cmd
# system(cmd)
cmd="mv "file" subdir_"n
print cmd
# system(cmd)
}
return
}
BEGIN{ if( (c+0) == 0) exit }
{ first_fit(,) }
END { print "REPORT:"
print "Created",n,"directories"
for(i=1;i<=n;++i) print "- subdir_"i,":", c-b[i],"bytes",bc[i],"files"
}
然后执行一行:
$ find . -type f -iname '*pdf' -printf "%s %p\n"
这将创建一个文件列表,其前面的文件大小以字节为单位。类似于:
8 file_1
1 file_2
8 file_3
4 file_4
4 file_5
4 file_6
10 file_7
...
现在您可以运行以下内容:
$ find . -type f -iname '*pdf' -printf "%s %p\n" \
| awk -v c=100000 -f bin_packing.awk
在上面的行中,您将值 c
设置为目录可以具有的最大大小(以字节为单位)。上面的值c=100000
只是一个例子。
这将创建如下输出:
...
mv file_47 subdir_6
mv file_48 subdir_6
mv file_49 subdir_5
mv file_50 subdir_6
REPORT:
Created 6 directories
- subdir_1 : 49 bytes 12 files
- subdir_2 : 49 bytes 9 files
- subdir_3 : 49 bytes 8 files
- subdir_4 : 49 bytes 8 files
- subdir_5 : 48 bytes 8 files
- subdir_6 : 37 bytes 5 files
如果您喜欢所看到的内容,可以考虑删除 bin_packing.awk
脚本中的评论。
注意: 这显然假设您的文件名是正常的。 IE。没有有趣的字符,也没有空格。
我有一个很大的目录 files_pdf
,其中包含 110 000 个 pdf 文档。这些文档中的每一个都有不同的文件大小。
我想将所有这些文档重新分发到一组子目录中,以便所有子目录的总累积大小大约 相同。我不想将文件拆分成多个部分。
我试过:
split -b 4000k myfile segment
但在某些情况下它会破坏我的 PDF。
基于 bin-packing First-fit 算法的解决方案可能如下所示。
创建名为 bin_packing.awk
的文件:
function first_fit(v, file) {
# find first bin that can accomodate the volume
for (i=1; i<=n; ++i) {
if (b[i] > v) {
b[i] -= v
bc[i]++
cmd="mv "file" subdir_" i
print cmd
# system(cmd)
return
}
}
# no bin found, create new bin
if (i > n) {
b[++n] = c - v
bc[n]++
cmd="mkdir subdir_"n
print cmd
# system(cmd)
cmd="mv "file" subdir_"n
print cmd
# system(cmd)
}
return
}
BEGIN{ if( (c+0) == 0) exit }
{ first_fit(,) }
END { print "REPORT:"
print "Created",n,"directories"
for(i=1;i<=n;++i) print "- subdir_"i,":", c-b[i],"bytes",bc[i],"files"
}
然后执行一行:
$ find . -type f -iname '*pdf' -printf "%s %p\n"
这将创建一个文件列表,其前面的文件大小以字节为单位。类似于:
8 file_1
1 file_2
8 file_3
4 file_4
4 file_5
4 file_6
10 file_7
...
现在您可以运行以下内容:
$ find . -type f -iname '*pdf' -printf "%s %p\n" \
| awk -v c=100000 -f bin_packing.awk
在上面的行中,您将值 c
设置为目录可以具有的最大大小(以字节为单位)。上面的值c=100000
只是一个例子。
这将创建如下输出:
...
mv file_47 subdir_6
mv file_48 subdir_6
mv file_49 subdir_5
mv file_50 subdir_6
REPORT:
Created 6 directories
- subdir_1 : 49 bytes 12 files
- subdir_2 : 49 bytes 9 files
- subdir_3 : 49 bytes 8 files
- subdir_4 : 49 bytes 8 files
- subdir_5 : 48 bytes 8 files
- subdir_6 : 37 bytes 5 files
如果您喜欢所看到的内容,可以考虑删除 bin_packing.awk
脚本中的评论。
注意: 这显然假设您的文件名是正常的。 IE。没有有趣的字符,也没有空格。