Сортировка файлов в каталогах по названию - PullRequest
2 голосов
/ 05 октября 2010

У меня есть несколько каталогов, которые содержат много файлов.Поскольку некоторые из них приближаются к 600-килобайтным файлам, они стали основной проблемой.Просто перечисление файлов постепенно становится основным узким местом в приложениях, обрабатывающих их.

Файлы называются так: id_date1_date2.gz Я решил разбить файлы на несколько меньших, в зависимости от первой части., "id".

Поскольку один и тот же идентификатор может отображаться в большом количестве файлов, и один и тот же идентификатор уже появляется в нескольких каталогах, мне нужно отслеживать, какие идентификаторы файлов были скопированы,и из чего реж.В противном случае я бы сделал то же самое, скопировав безумное количество раз или пропустив идентификатор X при копировании из dir Y, если он уже скопирован из dir 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, вероятно, является проблемой здесь.

Некоторый прогресс: я пытался записать каждый ключ в файл, и после каждой итерации я вместо этого считывал этот файл в массив.Это, очевидно, действительно ужасно, но, похоже, это достигло моей цели.Может быть, это становится чрезвычайно медленным, так как я обработал несколько тысяч идентификаторов.Будет обновлено позже.

Для кого-то, кто может найти это в будущем, вот последний сценарий:

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 сейчас, когда ассоциативный массив работает должным образом, и я не совсем понимаю, зачем мне нужен oldName var.

Ответы [ 2 ]

1 голос
/ 05 октября 2010

Если значение в $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 голосов
/ 05 октября 2010

Опция -n для cp очень полезна в подобных ситуациях.Это позволяет вам не беспокоиться, если файл уже находится в месте назначения.

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

Это в основном делает случай, когда вы говорите о том, что вы выполняете одну и ту же работу дважды, исчезает.Вы можете разделить свои проблемы на перемещение всех файлов и только перемещение файлов, которые не были перемещены ранее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...