如何在UNIX上将包含潜在的数百万个文件的非常大的目录拆分成一些自定义的最大数量的文件(如每个目录100个)的较小目录?
奖金点,如果你知道一个方法有wget
下载文件到这些子目录自动。 因此,如果www.example.com
顶层path中有100万个.html
页面,
/1.html /2.html ... /1000000.html
而我们只需要每个目录100个文件,就会把它们下载到类似的文件夹中
./www.example.com/1-100/1.html ... ./www.example.com/999901-1000000/1000000.html
只有真正需要能够在wget
下载文件之后才能在文件夹上运行UNIX命令,但是如果可以在wget
下载文件时执行此操作,我很想知道!
你可以通过几个循环来执行这个操作,至少对于文件名的数字部分来说是这样的。 我认为这样做是一个单一的过程乐观。
#! /bin/bash for hundreds in {0..99} do min=$(($hundreds*100+1)) max=$(($hundreds*100+100)) current_dir="$min-$max" mkdir $current_dir for ones_tens in {1..100} do current_file="$(($hundreds*100+$ones_tens)).html" #touch $current_file mv $current_file $current_dir done done
我做了性能测试,首先注释掉mkdir $current_dir
和mv $current_file $current_dir
并取消注释touch $current_file
。 这创建了10000个文件(1000000个文件的目标的百分之一)。 一旦这些文件被创建,我就回到了脚本,如下所示:
$ time bash /tmp/test.bash 2>&1 real 0m27.700s user 0m26.426s sys 0m17.653s
只要不跨文件系统移动文件,每个mv
命令的时间应该是不变的,所以你应该看到相似或更好的性能。 缩放到一百万个文件将会给你大约27700秒,即46分钟。 有几种优化的途径,例如在一个命令中移动给定目录的所有文件,或者删除内部for循环。
做'wget'来抓取一百万个文件将花费比这更长的时间,并且几乎肯定会需要一些优化; 仅在http头文件中保留带宽将使运行时间缩短数小时。 我不认为shell脚本可能是这个工作的正确工具; 在cpan上使用诸如WWW :: Curl之类的库将更容易优化。
另外一个选择:
i=1;while read l;do mkdir $i;mv $l $((i++));done< <(ls|xargs -n100)
或者使用parallel
:
ls|parallel -n100 mkdir {#}\;mv {} {#}
-n100
取100个参数, {#}
是作业的序列号。
要使ls | parallel更加实用,请在目标dir中添加一个变量赋值:
DST=../brokenup; ls | parallel -n100 mkdir -p $DST/{#}\;cp {} $DST/{#}
注意: cd <src_large_dir>
在执行之前。
上面定义的DST将包含当前目录文件的副本,但每个子目录最多为100个。