2010-10-05 52 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

相關問題