簡體   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