Reutilizando uma variável

1

Eu estava quebrando a cabeça por um dia ainda não consegui.

Eu tenho este script:

#!/bin/ksh

fname=$1

for batchname in $(grep -i "Processing batch" $fname | cut -d "'" -f2)
do
Batch_state='grep -c -i "Batch '$batchname' was successful" $fname'
if [[ "$Batch_state"  -ge 1 ]];then
{
S_Time='awk '/[0-9]_[0-9].*successful/{getline;getline;getline;print}' $fname | awk '{print $2}''
E_Time='awk '/[0-9]_[0-9].*successful/{getline;getline;getline;getline;print}' $fname | awk '{print $2}''
echo -e $batchname"\t"$S_Time"\t"$E_Time
}
else
{
echo $batchname encountered an error
}
fi
done

Saída este código está produzindo:

02_1231324      14:29:04 15:29:11   14:32:19 15:33:11
79_3097935      14:29:04 15:29:11   14:32:19 15:33:11

Saída desejada:

02_1231324      14:29:04    14:32:19
79_3097935      15:29:11    15:33:11 

Entrada de amostra:

2013/06/11 14:29:04 <0999> (725102)
Creating batch '02_1231324.0'...
2013/06/11 14:29:04 <0999> (725102)
Batch '02_1231324' was successful
2013/06/11 14:29:04 <0999> (725102)
TMR:Child ZERO, 160 Docs 320 Pgs 3874 KByts Tot 0.42 WAL 0.10 WALIO 0.15 IO 0.03 secs
2013/06/11 14:29:04 <0999> (725102)  Processing batch '02_1231324'
2013/06/11 14:32:19 <0999> (725102)
Total in batch: 160 documents using 4 KBytes
2013/06/11 15:29:11 <0999> (725102)
Creating batch '79_3097935.0'...
2013/06/11 15:29:11 <0999> (725102)
Batch '79_3097935' was successful
2013/06/11 15:29:11 <0999> (725102)
TMR:Child ZERO, 160 Docs 320 Pgs 3874 KByts Tot 0.42 WAL 0.10 WALIO 0.15 IO 0.03 secs
2013/06/11 15:29:11 <0999> (725102)  Processing batch '79_3097935'
2013/06/11 15:33:11 <0999> (725102)
Total in batch: 160 documents using 4 KBytes
TMR:Child ZERO, 160 Docs 320 Pgs 3874 KByts Tot 0.42 WAL 0.10 WALIO 0.15 IO 0.03 secs
2013/06/11 13:26:57 <0999> (725102)  Processing batch '12_2013162201'
2013/06/11 13:26:57 <0999> (725102)
Total in batch: 160 documents using 4 KBytes

Então, o que há de errado com o meu script? Como posso obter o resultado desejado?

    
por ramp 11.10.2013 / 15:05

4 respostas

3

Você provavelmente quer algo assim para analisar seu log:

#!/bin/awk -f
{
    if (/was successful/) {
        bn = $2;
        gsub(/'/, "", bn);
        succ[bn] = 1;
    }
    if (/Processing batch/) {
        bn = $7;
        gsub(/'/, "", bn);
        if (bn in succ) {
            succ[bn,",s"] = $2;
            getline
            succ[bn,",e"] = $2;
        } else
            fail[bn] = 1;
    }
}
END {
    for (val in succ)
        if (val !~ /,/)
            print val " " succ[val,",s"] " " succ[val,",e"];
    for (val in fail)
        print val " encountered an error";
}

Seu script original ligeiramente reduzido para apenas 1 awk chamar sob algumas suposições 1 estritas sobre a estrutura de seus dados de entrada).

#!/bin/ksh

fname=$1

for batchname in $(grep -i "Processing batch" $fname | cut -d "'" -f2); do
    Batch_state='grep -c -i "Batch '$batchname' was successful" $fname'
    if [[ "$Batch_state"  -ge 1 ]]; then
        awk -v b=$batchname '
{
    if ($0 ~ "Processing.*" b) {
        s = $2;
        getline;
        e = $2;
        print b " " s " " e;
        exit
    }
}' $fname
    else
        echo $batchname encountered an error
    fi
done

Versão mais curta usando grep -A ( -A é uma extensão GNU que seleciona a linha correspondente e um número - 1 por padrão - das linhas seguintes):

#!/bin/ksh

fname=$1

for batchname in $(grep -i "Processing batch" $fname | cut -d "'" -f2); do
    Batch_state='grep -c -i "Batch '$batchname' was successful" $fname'
    printf "%s" $batchname
    if [[ "$Batch_state"  -ge 1 ]]; then
        grep -A1 "Processing batch '$batchname'" $fname | cut -f2 -d" " | fmt
    else
        printf "encountered an error\n"
    fi
done

Mas estes ainda estão processando o arquivo 3 vezes . Veja a resposta de ChuckCottrill sobre como isso pode ser feito.

1 parece que os lotes não são processados em paralelo, e o que você quer é na verdade a linha contendo Processing batch e a linha depois disso.

    
por 11.10.2013 / 18:22
3

Este comando irá atribuir o conteúdo de uma linha para x, (concordou)

x=awk '/[0-9]_[0-9].*successful/{getline;getline;getline;print}' log filename | awk '{print $2}'
echo "$x"
2341

Você processa o arquivo inteiro três vezes, mas pode digitalizá-lo uma vez e extrair tudo o que precisa.

Suponha que você processe o arquivo inteiro e conte as linhas. Você usou awk, mas aqui está um script em perl, fazendo tudo em poucas linhas,

#!/bin/env perl
use strict;
use warnings;

if( $#ARGV < 0 ) { die "no filename"; }
my ($batchname,$S_Time,$E_Time);
my ($success); #batch successul/failed?
my ($num,$pnum); #linenumber, processing line number
my ($fn,$fh,$line,@cols);

foreach $fn (@ARGV)
{
    if( !open($fh,"<$fn") ) { print "error: cannot open $fn\n"; next; }
    $success=0; $num=0; $pnum=-1; #line number
    while($line = <$fh>)
    {
        if( $line =~ /Batch.*\'([\d_]+)\'.*was successful/ )
        {
            $batchname = $1; $success = 1;
        }
        if( $line =~ /Processing batch \'([\d_]+)\'/ )
        {
            $batchname = $1; $pnum = $num;
        }
        if( $pnum > 0 ) {
        my @cols = split(/\s/,$line);
        if($num==$pnum) { $S_Time=$cols[1]; }
        if($num==$pnum+1) { $E_Time=$cols[1]; }
        }
        $num++;
    }
    if( $success ) { print "$batchname\t$S_Time\t$E_Time\n"; }
    else { print "$batchname encountered an error\n"; }
}

Do arquivo de entrada / registro de amostra fornecido:

2013/06/11 13:26:57 <0999> (725102)
Creating batch '12_2013162201.0'...
2013/06/11 13:26:57 <0999> (725102)
Batch '12_2013162201' was successful
2013/06/11 13:26:57 <0999> (725102)
TMR:Child ZERO, 160 Docs 320 Pgs 3874 KByts Tot 0.42 WAL 0.10 WALIO 0.15 IO 0.03 secs
2013/06/11 13:26:57 <0999> (725102)  Processing batch '12_2013162201'
2013/06/11 13:26:57 <0999> (725102)
Total in batch: 160 documents using 4 KBytes

Aqui está a saída,

$ ./extractbatch.pl extractbatch.log 
12_2013162201   13:26:57        13:26:57

E aqui está a versão do awk (desculpe pelo perl primeiro, estou um pouco enferrujado no meu awk),

#!/bin/awk -f
BEGIN {
    success=0; batchname="none";
    num=0; pnum=-1;
    S_Time="null"; E_Time="null";
}
#/Batch*was successful/ {
/was successful/ {
    batchname = $2; success = 1;
    printf "1: %s\n",batchname;
}
#/Processing batch */ {
/Processing/ {
    batchname = $7; pnum = num;
    printf "2: %s\n",batchname;
}
{
    if(num==pnum) S_Time=$2;
    if(num==pnum+1) E_Time=$2;
    num++;
}
END {
    if( success>0 ) { printf "%s\t%s\t%s\n",batchname,S_Time,E_Time; }
    else { printf "%s encountered an error\n",batchname; }
}

Note que a versão perl faz mais.

    
por 11.10.2013 / 18:08
2

Isso funciona usando as mesmas ideias básicas do seu script:

#!/bin/ksh

fname=$1
for batchname in $(grep -i "Processing batch" $fname | cut -d "'" -f2)
do
    Batch_state='grep -c -i "Batch '$batchname' was successful" $fname'
    if [[ "$Batch_state"  -ge 1 ]];then
    S_Time=$(grep "Processing.*$batchname" $fname | awk '{print $2}')
    E_Time=$(grep -A 1 "Processing.*$batchname" $fname | tail -n 1 | awk '{print $2}')
    echo -e "$batchname\t$S_Time\t$E_Time"
else
    echo $batchname encountered an error
fi
done
    
por 11.10.2013 / 18:08
0

Você pode usar unset em suas variáveis a cada vez através de seu loop for. unset faz o que diz na lata, desfaz uma variável.

-bash-4.2$ export FOO=true
-bash-4.2$ echo $FOO
true
-bash-4.2$ unset FOO
-bash-4.2$ echo $FOO

-bash-4.2$
    
por 13.10.2013 / 16:44