Substituir sequência por índice sequencial


9

Alguém pode sugerir uma maneira elegante de fazer isso?

Entrada:

test  instant  ()

test  instant  ()

...
test  instant  ()    //total 1000 lines

a saída deve ser:

test      instant1  ()

test      instant2  ()

test      instant1000()

As linhas vazias estão nos meus arquivos de entrada e há muitos arquivos no mesmo diretório que eu preciso processar de uma só vez.

Eu tentei isso para substituir muitos arquivos no mesmo diretório e não funcionou.

for file in ./*; do perl -i -000pe 's/instance$& . ++$n/ge' "$file"; done

erros:

Substitution replacement not terminated at -e line 1.
Substitution replacement not terminated at -e line 1.

e eu também tentei isso: perl -i -pe 's/instant/$& . ++$n/ge' *.vs

Funcionou, mas o índice continuou aumentando de um arquivo para outro. Eu gostaria de redefinir isso para 1 para o arquivo diff. alguma sugestão boa?

find . -type f -exec perl -pi -e 's/instant/$& . ++$n{$ARGV}/ge' {} +

funciona, mas substituiu todos os outros arquivos não devem ser substituídos. Prefiro substituir apenas os arquivos por "* .txt".


E todos eles consistem exclusivamente em linhas em branco ou test instant ()?
terdon

Coloquei as linhas com espaçamento duplo de novo, geralmente são um sinal de novos usuários que não sabem como usar a marcação deste site, por isso o terdon os removeu enquanto recuava adequadamente o bloco de conteúdo do arquivo para que ele fosse exibido como conteúdo do arquivo. Espero que esteja tudo bem agora.
Timo

Respostas:


13
perl -pe 's/instant/$& . ++$n/ge'

ou com GNU awk:

awk -vRS=instant '{$0=n$0;ORS=RT}++n'

Para editar os arquivos no local, adicione a -iopção a perl:

perl -pi -e 's/instant/$& . ++$n{$ARGV}/ge' ./*

Ou recursivamente:

find . -type f -exec perl -pi -e 's/instant/$& . ++$n{$ARGV}/ge' {} +

Explicações

perl -pe 's/instant/$& . ++$n/ge'

-pé processar a entrada linha por linha, avaliar a expressão passada -epara cada linha e imprimi-la. Para cada linha, substituímos (usando o s/re/repl/flagsoperador) instantpor si ( $&) e o valor incrementado de uma variável ++$n. A gbandeira é fazer a substituição em todo o mundo (e não apenas uma vez), e epara que a substituição seja interpretada como código Perl para e valuate (não uma seqüência fixa).

Para edição no local em que uma chamada perl processa mais de um arquivo, queremos $nredefinir a cada arquivo. Em vez disso, usamos $n{$ARGV}(onde $ARGVestá o arquivo processado no momento).

O awkque merece um pouco de explicação.

awk -vRS=instant '{$0=n$0;ORS=RT}++n'

Estamos usando a capacidade do GNU awkpara separar registros em cadeias arbitrárias (mesmo regexps). Com -vRS=instant, definimos o separador de registros como instant. RTé a variável que contém o que foi correspondido RS, normalmente, instantexceto o último registro onde será a sequência vazia. Na entrada acima, os registros ( $0) e terminadores de registro ( RT) são ( [$0|RT]):

[test  |instant][  ()
test  |instant][  ()
...
test  |instant][  ()    //total 1000 lines|]

Então, tudo o que precisamos fazer é inserir um número incremental no início de cada registro, exceto o primeiro.

Qual é o que fazemos acima. Para o primeiro registro, nestará vazio. Definimos ORS (o separador de registros de saída ) como RT, para que seja awk impresso n $0 RT. Faz isso na segunda expressão ( ++n), que é sempre uma condição avaliada como verdadeira (um número diferente de zero) e, portanto, a ação padrão (de impressão $0 ORS) é executada para cada registro.



4

sedrealmente não é a melhor ferramenta para o trabalho, você deseja algo com melhores recursos de script. Aqui estão algumas opções:

  • perl

    perl -000pe 's/instant/$& . $./e' file 

    O -pmeio "imprime todas as linhas" após aplicar o script fornecido -e. As -000voltas no "modo de parágrafo" para registros (linhas) são definidos pela nova linha consecutiva ( \n) caracteres, isso permite que lidar com linhas espaçadas duplas corretamente. $&é o último padrão correspondente e $.é o número da linha atual do arquivo de entrada. O ein s///eme permite avaliar expressões no operador de substituição.

  • awk (isso pressupõe que seus dados são exatamente como mostrados, com três campos separados por espaço)

    awk '{if(/./) print $1,$2 ++k,$3; else print}' file 

    Aqui, incrementamos a kvariável kapenas se a linha atual não estiver vazia; /./nesse caso, também imprimimos as informações necessárias. Linhas vazias são impressas como estão.

  • várias conchas

     n=0; while read -r a b c; do 
       if [ "$a" ] ; then 
          (( n++ ))
          printf "%s %s%s %s\n" "$a" "$b" "$n" "$c"
       else
          printf "%s %s %s\n" "$a" "$b" "$c"
       fi
     done < file 

    Aqui, cada linha de entrada é dividida automaticamente no espaço em branco e os campos são salvos como $a, $be $c. Em seguida, dentro do loop, $cé aumentado em um para cada linha que $anão está vazia e seu valor atual é impresso ao lado do segundo campo $b.

NOTA: todas as soluções acima assumem que todas as linhas no arquivo têm o mesmo formato. Caso contrário, a resposta de @ Stephane é o caminho a percorrer.


Para lidar com muitos arquivos e supondo que você queira fazer isso com todos os arquivos no diretório atual, você pode usar o seguinte:

for file in ./*; do perl -i -000pe 's/instant/$& . $./e' "$file"; done

CUIDADO: Isso pressupõe nomes de arquivos simples, sem espaços, se a necessidade de lidar com algo mais complexo, ir para (assumindo ksh93, zshou bash):

find . -type f -print0 | while IFS= read -r -d ''; do
    perl -i -000pe 's/instant/$& . $./e' "$file"
done

o script perl funciona. no entanto, há um pequeno problema se as linhas tiverem espaço duplo.
user3342338

@ user3342338 sim, isso aumentará o contador, pois estou usando o número da linha atual. Essa é uma abordagem muito ingênua, pois eu disse que a Stephane's é mais robusta. Nenhuma delas funciona se você tiver linhas em branco ou se alguma delas se desviar do que você mostra.
terdon

@ user3342338 ver resposta atualizada. Todos devem agora funcionar para arquivos com espaço duplo.
terdon

Ótima resposta e a opção de métodos alternativos !! Graças
Madivad
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.