2010-10-05 49 views
2

我有几个包含大量文件的目录。由于其中一些正在接近60万个文件,它们已经成为一个主要的难题。列出文件正在慢慢成为应用程序处理的主要瓶颈。根据文件名将文件分类到目录中

文件的命名是这样的: id_date1_date2.gz 我已经决定将文件分割成几个较小的一个,根据第一部分,“ID”。

由于同一个ID可能出现在大量文件中,并且相同的ID已经出现在几个目录中,所以我需要跟踪哪些文件ID已被复制,以及来自哪些目录。 否则,我会最终做同样的复制一个疯狂的时间量,或从方向Y复制时丢失id X,如果已经从方向Z复制。

我写了一个脚本来完成此操作。一些调试包括

#!/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。

+0

你必须使用bash,或者是perl,python,......可以接受的选择吗? – 2010-10-05 15:01:46

+0

我开始考虑使用php自己,因为我熟悉这一点。只要脚本足够可读,我就可以知道它能做到我想要的,所以任何语言都可以。 – Claes 2010-10-05 15:04:28

回答

1

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

declare -A copied 

附加注释:

你在一些地方参数扩展,而在其他sed。你可以在所有情况下使用大括号扩展。

我会建议,而不是做引述像$var"literal"$var,做这样"${var}literal${var}"或在字面不会含糊解释为可以忽略括号中的变量名称的一部分的情况:"literal$var"

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

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

GNU find有一个正则表达式功能,您可以使用,而不是grep

应该引用包含文件名的所有变量名称。

+0

我使用bash 4,但之前没有使用关联数组,声明对我来说是新的,似乎有所作为,谢谢!我将更正我的变量以使用适当的引用。我实际上最初尝试过-v,但由于我无法弄清楚的原因,它失败了。我会看到有关替换那个丑陋的sed。我不知道我可以用find来使用正则表达式。我也无法完成它的工作,但是如果我放弃$,那么-name接受我的正则表达式。你发布的信息最多。再次感谢你。 – Claes 2010-10-06 07:03:37

0

cp的-n选项在这种情况下非常有用。它可以让你不用担心,如果一个文件已经在目的地。

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

这基本上让你谈论你在哪里做同样的工作两次消失。您可以将问题分解为移动所有文件,并只移动之前未移动的文件。

+0

谢谢,我已经添加了该脚本。虽然这确实改善了情况,但它看起来仍然很难看。 cp仍然需要对单个文件进行数千次检查。然后再次,我不知道在bash中检查是否快得多。 – Claes 2010-10-06 07:09:37

相关问题