Bash: Группировка файлов по имени

Из документации LVM, которая подходит легко на Google:

LVM поддерживает маленький журнал, который он использует для отслеживания, которых регионы находятся в синхронизации с зеркалом или зеркалами. По умолчанию этот журнал сохранен на диске, который сохраняет его персистентным через перезагрузки. Можно указать вместо этого, что этот журнал сохранен в памяти с - corelog аргумент; это избавляет от необходимости дополнительное устройство журналирования, но она требует, чтобы все зеркало было ресинхронизировано в каждой перезагрузке.

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

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

3
02.10.2012, 16:46
2 ответа

Предположение, что нет никакого "\n" символа в именах файлов:

find . -name '*_*_[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]_*.gz' | perl -le '
    use strict;
    use warnings;
    my %hash;
    while(<>) {
        chomp;
        my($group)=/^([^_]+_[^_]+_[0-9]{11})/;
        $group=~s/[0-2]$/00/;
        $group=~s/[3-5]$/30/;
        push @{$hash{$group}},$_;
    }
    while(my($group,$files_arr_ref)=each%hash) {
        print "processing group $group";
        for my$file (sort @{$files_arr_ref}) {
            print "processing file $file";
            # do system command calls here; for example
            # system "gzip -cd \"$file\" >> $group.txt";
        }
    }
' 

Править: несколько изменений после предложений Craig. Первая идея состояла в том, чтобы только использовать жемчуг для массивов и хешей, наконец это более ясно сделать все. @ARGV является списком пути для передачи для нахождения. Например, если название сценария является script.pl:

script.pl ${sourceFolder}

#!/usr/bin/perl

use strict;
use warnings;
use File::Find;

my %hash;

sub wanted {
    return unless /^([^_]+_[^_]+_[0-9]{11})/;
    my$group=$1;
    $group=~s/[0-2]$/00/;
    $group=~s/[3-5]$/30/;
    push @{$hash{$group}},$_;
}

File::Find::find(\&wanted, @ARGV);

while(my($group,$files_arr_ref)=each%hash) {
    print "processing group $group\n";
    ### do system command calls here; for example
    # system "rm $group.txt";
    ### or just use perl
    # unlink $group.'.txt';
    for my$file (sort @{$files_arr_ref}) {
         print "processing file $file\n";
         ### and other system command calls here; for example
         # system "gzip -cd $file >> $group.txt";
    }
    ### and here; for example
    # system "gzip $group.txt";
}
3
27.01.2020, 21:14
  • 1
    +1. Хороший, но Вы могли использовать File::Find модуль (включенный с жемчугом в эти дни, не должны даже выбирать его от CPAN) вместо find или Вы могли открыть канал от находки, например. open(FIND,'-|','/usr/bin/find','.','name',...); (см. perlipc страница справочника). Так или иначе у Вас был бы сценарий жемчуга, а не минимальная обертка оболочки вокруг жемчуга (таким образом, можно использовать perl -w -c к проверке синтаксиса это и подсветке синтаксиса энергии работало бы правильно, и т.д.). BTW, я не думаю жемчуг -l делает что-либо полезное, здесь... безопасное, но не необходимый. –  cas 03.10.2012, 13:37
  • 2
    Какой безумный набор [0-9] s! Я, вероятно, предпочел бы a find -regex вместо этого в первой строке первого решения (при запоминании, что я должен был бы предварительно ожидать спецификацию пути с тех пор find -regex не поиск, а соответствие). А-ч –  syntaxerror 20.08.2013, 12:01

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

Я пошел бы об этом просто распечатывание соответствующих файлов и отсортировал бы их согласно времени Unix (нашел что работы лучше, чем нормальный / человекочитаемое время):

find $PWD -type f -printf '%T@ %p\n' | sort -nb

затем Вы могли сохранить время Unix первого члена группы с 30 минутами как контрольная точка относительно того, когда эти 30 минут запускают, вычисляют различие к метке времени Unix текущего файла, если> 1800 затем создает новую группу, еще добавляют к текущей группе. Что-то вдоль тех строк:

#!/bin/bash
#1800 s = 30 min
#unix time 86400s = 1 day

fileList=$(find $PWD -type f -printf '%T@ %p\n' | sort -nb)
## for debugging:
# fileList=$(find $PWD -type f -printf '%T@ %t %p\n' | sort -nb)

org_IFS=$IFS
IFS=$'\n'
group_start_time=0
for line in $fileList; do
    current_time=$(echo $line | awk '{print $1}')
    if [ $group_start_time -eq 0 ] ; then
        group_start_time=$current_time
    else
        delta=$(($current_time - $group_start_time))
        #echo $delta
        if [ $delta -lt 1801 ] ; then
            echo $line
        else
            echo -e "\nnew group:\n$line"
            group_start_time=$current_time
        fi
    fi
done
IFS=$org_IFS

оттуда можно просто сделать перенаправление пути к файлу к любому файлу, который Вы хотите (использующий>>). и позже выполненный mv в том списке файлов к их соответствующим каталогам.

Я надеюсь, что это помогает так или иначе.:)

Править: Я изменил сценарий, таким образом, что он пишет группам log.gz файлов в файлы в источнике (Ваш /opt/rename/ ) в целевом каталоге (то, которое я принял, было Вашим /opt/send/combined/ каталог). Ниже измененный код:

#!/bin/bash
#1800 s = 30 min
#unix time 86400s = 1 day

sourceFolder="/opt/rename/"
target="/opt/send/combined/"

path_to_file=$target
current_file="ORACLE_gprtcp_000.log.gz"

fileList=$(find $sourceFolder -type f -name '*.log.gz' -printf '%T@ %p\n' | sort -nb)
## for debugging:
# fileList=$(find $PWD -type f -printf '%T@ %t %p\n' | sort -nb)

echo ${fileList[0]}

org_IFS=$IFS
IFS=$'\n'
group_start_time=0

for line in $fileList; do
    current_time=$(echo $line | awk '{print $1}')
    if [ $group_start_time -eq 0 ] ; then
        group_start_time=$current_time
        hr_time=$( date -d @$current_time +%F_%0k%0M )
        current_file="ORACLE_gprtcp_"$hr_time".log.gz"
    else
        delta=$(($current_time - $group_start_time))
        #echo $delta
        if [ $delta -lt 1801 ] ; then
            # just append file path to current_file
            echo $line | awk '{print $2}' >> $path_to_file"/"$current_file
            echo $line
        else
            # construct new filename based on time of the first member of the group
            hr_time=$( date -d @$current_time +%F_%0k%0M )
            current_file="ORACLE_gprtcp_"$hr_time".log.gz"

            # create file, append file path to current_file
            echo $line | awk '{print $2}' >> $path_to_file"/"$current_file
            echo -e "\nnew group:\n$line"

            group_start_time=$current_time
        fi
    fi
done

IFS=$org_IFS
3
27.01.2020, 21:14

Теги

Похожие вопросы