繁体   English   中英

根据文件名将文件排序到目录中

[英]Sorting files into directories based on their name

我有一些包含很多文件的目录。 随着其中一些文件接近60万个文件,它们已成为处理的主要难题。 仅列出文件正逐渐成为处理文件的应用程序中的主要瓶颈。

文件的命名如下:id_date1_date2.gz我已决定将文件分成几个较小的文件,具体取决于第一部分“ id”。

由于相同的ID可能显示在大量文件中,并且相同的ID已经显示在多个目录中,因此我需要跟踪已复制的文件ID,以及从哪些目录复制。 否则,我最终会进行相同的复制,而复制的次数是疯狂的,或者如果从目录Y复制过来的话,如果从目录Z复制了,则会丢失idX。

我已经编写了一个脚本来完成此任务。 包括一些调试

#!/bin/bash  
find /marketdata -maxdepth 2 -type d | grep "[0-9]\.[0-9][0-9][0-9]$" | sort | #head -n2 | tail -n1 |
    while read baseDir; do

    cd $baseDir;
    echo $baseDir > tmpFile;
    find . -type f | grep -v "\.\/\." | #sort | head -n4 |
            while read file; do
            name=$(awk 'BEGIN {print substr("'"$file"'", 3,index("'"$file"'", "_")-3 )}');

            dirkey=${baseDir//[\/,.]/_}"_"$name;
            if [ "${copied[$dirkey]}" != "true" ]; then
                    echo "Copying $baseDir/$name with:";
                    echo mkdir -p $(sed 's/data/data4/' tmpFile)/$name;
                    #mkdir -p $(sed 's/data/data4/' tmpFile)/$name;
                    oldName=$baseDir/$name"_*";
                    echo cp $oldName "$(sed 's/data/data4/' tmpFile)/$name/";
                    #cp $oldName "$(sed 's/data/data4/' tmpFile)/$name/";
                    echo "Setting $dirkey to true";
                    copied[$dirkey]="true";
            else
                    echo "$dirkey: ${copied[$dirkey]}"
                    sleep 1
            fi
    done;

    rm tmpFile;
done

这里的问题是,从第一次复制开始,复制中所有键的值似乎都是正确的,因此我对bash数组的处理可能是这里的问题。

一些进展:我尝试将每个键写入文件,并且在每次迭代时,我都会将该文件读入数组。 这显然很丑陋,但看起来可以实现我的目标。 可能是因为我已经处理了数千个id,这变得非常慢。 稍后将更新。

对于将来可能会发现此问题的其他人,下面是最终脚本:

declare -A copied

find /marketdata -maxdepth 2 -type d -name "[0-9]\.[0-9][0-9][0-9]" | sort | #head -n3 | tail -n1 |
    while read baseDir; do

    cd $baseDir;
    find . -type f | grep -v "\.\/\." | sort | #head -n100 |
            while read file; do
            length=$(expr index "$file" "_");
            name=${file:2:$((length - 3))};

            dirkey=${baseDir//[\/,.]/_}"_"$name; 
            if [ "${copied[$dirkey]}" != "true" ]; then
                    echo "Copying ${baseDir}/${name} to ${baseDir//data/data4}/$name";
                    mkdir -p "${baseDir//data/data4}/$name";
                    oldName="${baseDir}/${name}_*";
                    cp -n $oldName "${baseDir//data/data4}/${name}/";
                    copied[$dirkey]="true";
            fi
    done;
done

没有awk,没有sed,更好的引用,没有将临时文件写入磁盘,更少的grep。 现在不确定关联数组是否正常工作,是否有必要进行dirkey hack操作,也不知道为什么我需要oldName var。

如果$dirkey中的值包含字母字符,则必须使用在Bash 4之前不可用的关联数组。如果使用Bash 4,并且键是字母数字而不是简单的数字,请在顶部添加以下内容您的脚本:

declare -A copied

附加评论:

您在某些地方使用参数扩展,而在其他地方使用sed 在(可能)所有情况下都可以使用括号扩展。

我建议不要像$var"literal"$var那样引用,或者像"${var}literal${var}"那样引用,或者在文字不会被模糊地解释为变量名的一部分的情况下,您可以省略花括号: "literal$var"

使用通过awk传递的变量而不是复杂的"'"引号: awk -v awkvar=$shellvar '{print awkvar}'

在循环中调用外部可执行文件会使事情减慢很多,尤其是一次只处理一个值(或数据行)的情况。 commands that I mentioned are examples of this. Also, your的'sed commands that I mentioned are examples of this. Also, your commands that I mentioned are examples of this. Also, your awk`命令可能能够转换为参数扩展形式。

GNU find具有正则表达式功能,可以代替grep使用。

所有包含文件名的变量名都应加引号。

cp的-n选项在这种情况下非常有用。 它使您不必担心文件是否已在目标位置中。

-n, --no-clobber
   do not overwrite an existing file (overrides 
   a previous -i option)

基本上,这样一来,您谈论两次重复进行相同工作的情况就会消失。 您可以将关注点分为移动所有文件和仅移动之前从未移动过的文件。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM