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.