Índice de incremento no arquivo

2

Tudo bem, parece que não consigo encontrar uma maneira de fazer o que preciso.

Digamos que eu tenha um arquivo de texto como este

(freqBiasL2[27])      
(SatBiasL1[27])       
(defSatBiasL2_L1[27]) 
(defSatBiasSlope[27]) 
(defSatBiasSigma[27]) 

(freqBiasL2[28])      
(SatBiasL1[28])       
(defSatBiasL2_L1[28]) 
(defSatBiasSlope[28]) 
(defSatBiasSigma[28]) 

(freqBiasL2[29])      
(SatBiasL1[29])       
(defSatBiasL2_L1[29]) 
(defSatBiasSlope[29]) 
(defSatBiasSigma[29])

e assim por diante. Eu quero mudar o índice entre colchetes [] de tal forma que cada índice i é = i + 3.

Eu tentei com uma combinação de loop e sed, mas não está funcionando

for i in {27..107..1}
do
    i_new=$((i+3))
    sed -e 's/\['$i'\]/\['$i_new'\]/' prova.txt 

done

O problema é que ele mudará os primeiros 27 para 30, mas nas próximas interações encontrará 2 blocos com índice 30 (o alterado e o original).

Como posso fazer isso sem sobrescrever os índices já alterados?

Ok, obrigado, edito minha pergunta para uma melhoria: Como posso fazer algo semelhante é se eu tenho 2 índices como:

(freqBiasL2[32][100])
(SatBiasL1[32][101])
(defSatBiasL2_L1[32][102])
(defSatBiasSlope[32][103])
(defSatBiasSigma[32][104])

e eu quero incrementar apenas o segundo índice ignorando o primeiro?

    
por Dad85 20.05.2016 / 10:35

5 respostas

6

Use perl:

perl -pe 's/(?<=\[)(\d+)(?=\])/$1+1/ge' prova.txt

Explicação:

  • -p significa repetir todas as linhas e imprimir o resultado depois de cada linha
  • -e define a expressão a ser executada em todas as linhas
  • s/from/to/ faz uma simples subestição
  • s/(\d+)/$1+1/ge corresponde a um ou mais dígitos, captura-o em $1 e, em seguida, o modificador e no final informa ao perl que a sequência de subseqüência é uma expressão: $1+1 substitui o valor $1 plus 1. g modifier significa fazer esta substituição globalmente, ou seja, mais de uma vez por linha.
  • (?<=\[) é uma asserção lookbehind de comprimento zero positiva. Isso significa que o que vem depois só coincide se for precedido por [ (que precisa ser escapado com \ , pois [ é um token especial em expressões regulares). A coisa de comprimento zero significa que não faz parte do que será substituído.
  • (?=\]) é uma asserção lookahead positiva de comprimento zero. Isso significa que o que vem antes só coincide se for seguido por ] (novamente escapou).

Então, isso levará todos os números entre [ e ] e incrementará esse número.

    
por 20.05.2016 / 10:50
3

Você também pode usar awk :

awk -F '[\[\]]' '{if ($2) { sub($2, $2 + 3)}} 1' prova.txt

Na verdade, isso pode ser ligeiramente reduzido para:

awk -F '[\[\]]' '$2 { sub($2, $2 + 3)} 1' prova.txt
    
por 20.05.2016 / 11:33
3

Eu sei que você já resolveu o seu problema, mas eu poderia tê-lo resolvido com uma modificação muito simples no seu código: invertendo a sequência que você passa por cima.

Usar {107..27..-1} (ou mais concisamente {107..27} ) teria sido suficiente para resolver seu problema, pois ao substituir 30, somente os 30 originais teriam sido encontrados, os 27 ainda não foram substituídos.

    
por 20.05.2016 / 14:44
2
perl -p -e 's/\[(\d+)\]/"[" . ($1+3) . "]"/ge' dad85.txt  

Este perl one-liner substitui qualquer número inteiro positivo ( \d+ ) entre colchetes com esse número aumentado em 3.

Ele usa o modificador e regexp para fazer com que perl avalie a parte de substituição da operação s/// como uma expressão.

Saída:

(freqBiasL2[30])
(SatBiasL1[30])
(defSatBiasL2_L1[30])
(defSatBiasSlope[30])
(defSatBiasSigma[30])

(freqBiasL2[31])
(SatBiasL1[31])
(defSatBiasL2_L1[31])
(defSatBiasSlope[31])
(defSatBiasSigma[31])

(freqBiasL2[32])
(SatBiasL1[32])
(defSatBiasL2_L1[32])
(defSatBiasSlope[32])
(defSatBiasSigma[32])
    
por 20.05.2016 / 10:52
0

Ok, eu acho que eu tenho uma solução para o índice duplo, bem como modificar o comando do cas. Isso faz o trabalho:

perl -p -e 's/\[(\d+)\]\[(\d+)\]/"[" . ($1) . "][" . ($2+40) . "]"/ge' prova.txt

Não sei por que preciso do . ($1) . (ponto com espaço em branco).

    
por 20.05.2016 / 12:35