在bash中基于扩展有效地移动50万个文件 脚本:

在bash中基于扩展有效地移动50万个文件 脚本:,bash,file-extension,file-recovery,Bash,File Extension,File Recovery,在Locky病毒肆虐的情况下,我工作的计算机中心发现,唯一的文件恢复方法是使用诸如Recuva之类的工具。现在的问题是,它将所有恢复的文件转储到一个目录中。我想将所有这些基于这些文件扩展名的文件分为几个类别。一个中的所有JPG另一个中的所有BMP。。。等等,我环顾了Stackoverflow,根据其他各种问题和回答,我成功地构建了一个小bash脚本(提供的示例),它可以做到这一点,但是需要花费很长时间才能完成,我想我把扩展搞砸了 代码: #/bin/bash path=$2#垃圾文件目录的起始路

在Locky病毒肆虐的情况下,我工作的计算机中心发现,唯一的文件恢复方法是使用诸如Recuva之类的工具。现在的问题是,它将所有恢复的文件转储到一个目录中。我想将所有这些基于这些文件扩展名的文件分为几个类别。一个中的所有JPG另一个中的所有BMP。。。等等,我环顾了Stackoverflow,根据其他各种问题和回答,我成功地构建了一个小bash脚本(提供的示例),它可以做到这一点,但是需要花费很长时间才能完成,我想我把扩展搞砸了

代码:
#/bin/bash
path=$2#垃圾文件目录的起始路径
var=0#处理了多少条记录
秒=0#重置时钟,以便我们可以计时事件
清楚的
echo“搜索$2的文件类型,然后将所有文件移动到分组文件夹中。”
#只想从第一级移动文件,因为目录是确定的
对于'find$2-maxdepth 1-类型f'中的文件`
做
#使用AWK拆分目录名的EXT

DIR=$(awk-F.{print$NF}'任何bash脚本的瓶颈通常是您启动的外部进程的数量。在这种情况下,您可以通过认识到您要移动的文件中有很大一部分都有一个共同的后缀,如
jpg
等,从而大大减少对
mv
的调用次数。从这些后缀开始

for ext in jpg mp3; do
    mkdir -p "$ext"
    # For simplicity, I'll assume your mv command supports the -t option
    find "$2" -maxdepth 1 -name "*.$ext" -exec mv -t "$ext" {} +
done
使用
-exec mv-t“$ext”{}+
意味着
find
将向对
mv
的每次调用传递尽可能多的文件。对于每个扩展名,这意味着对
find
的一次调用和对
mv
的最小调用次数

一旦这些文件被移动,您就可以开始一次分析一个文件

for f in "$2"/*; do
    ext=${f##*.}
    # Probably more efficient to check in-shell if the directory
    # already exists than to start a new process to make the check
    # for you.
    [[ -d $ext ]] || mkdir "$ext"
    mv "$f" "$ext"
done

在决定要做多少工作之前,确定公共扩展以最小化第二个
for
循环的迭代次数时,需要进行权衡。

我想你的问题是“如何使这更快?”专注于
find
mkdir
是您的理论基础,您认为您了解
mkdir
以及您在交互式观看脚本执行时看到的情况。如果您想让脚本执行得更快,您应该衡量这些部分的速度,以确定真正的瓶颈。除非您知道要移动的所有文件都有很好的文件名,没有空格或对shell有特殊意义的字符,否则您的
for
循环已被破坏。运行50万
awk
进程并不理想。请使用bash参数替换来获得扩展名。@chepner我有一种感觉,因为我有大量的扩展名ROR“无法统计”和“无法找到”之类的内容@MarkSetchell谢谢你提供的信息,我会仔细研究的。+1为了提高效率,考虑到我不需要一些文件,我可以调整它来删除所有DLL文件删除一块我不需要的文件,然后我们一对一地处理它们,只需一个文件目录,你甚至不需要
在这里查找
。只需
mv-t tgt*.glob
行(直到文件列表变得太大,然后
xargs
可能会很有用。我保留了
find
的功能,以便使用
-exec…+
动态决定每次调用
mv
时可以传递多少文件。如果我没有弄错的话,
xargs
被限制为指定固定的最大参数数,不管参数多少)参数的累计长度。@EtanReisner首先让脚本处理它的主要原因是
bash:/bin/mv:Argument list太长了
@drewmoney对。就像我说的,在你点击它之前,你很好,然后你可以使用
xargs
而不是
find
,尽管两者都使用得很好)是find(事实上,我认为单独安全/正确地使用
find
会稍微容易一些)。
for f in "$2"/*; do
    ext=${f##*.}
    # Probably more efficient to check in-shell if the directory
    # already exists than to start a new process to make the check
    # for you.
    [[ -d $ext ]] || mkdir "$ext"
    mv "$f" "$ext"
done