Duplicar, com algumas pequenas alterações, algumas linhas em um arquivo de texto

5

Estou tentando descobrir como replicar um único intervalo de linhas em um arquivo de texto. O intervalo começa com uma linha exclusiva no arquivo, mas o intervalo termina com uma linha que pode existir em vários locais no arquivo.

Veja algumas entradas de exemplo que preciso processar:

I have no imagination
so this sample text will
Common
be boring. But it does
demonstrate the problem
I am trying to solve.
Common
Hi mom!
This is a unique line.
And here is some more
text that should be copied
as well.
Common
Followed by text that should
not be copied.

As linhas que eu preciso duplicar e modificar estão em negrito para indicá-las aqui.

A saída de que preciso é:

I have no imagination
so this sample text will
Common
be boring. But it does
demonstrate the problem
I am trying to solve.
Common
Hi mom!
This is a changed line.
And here is different more
text that should be copied
as well.
Common
This is a unique line.
And here is some more
text that should be copied
as well.
Common
Followed by text that should
not be copied.

A saída adicional está em negrito para deixar claro.

Eu preciso obter o intervalo de linhas começando com a linha:

This is a unique line

e terminando com a linha:

Common

Esse intervalo de linhas deve ser inserido antes de antes do intervalo original de linhas. A cópia do intervalo de linhas correspondentes precisará ser modificada ligeiramente.

A linha "Comum" que encerra o intervalo pode ocorrer em vários locais dentro do arquivo.

Eu criei um script awk funcional, mas parece muito mais complicado do que precisa ser. Minhas habilidades awk são inexistentes.

/This is a unique line/{flag=1}
/Common/{
    if (flag > 0) {
        n=m;
        sub("some","different",n);
        sub("unique","changed",n);
        print n "\n" $0 "\n" m;
        m=""
    };
    flag=0
};
flag{
    if (length(m) > 0) {
        m=m "\n" $0
    } else {
        m=$0
    }
}
!flag{ print }

Existe uma maneira mais clara e menos detalhada de implementar isso? Estou aberto a outras opções além de awk . Só precisa ser um comando padrão disponível no macOS.

    
por rmaddy 18.05.2017 / 02:38

3 respostas

4
awk '/This is a unique line/,/Common/{
   H = H RS $0
   if ( $0 ~ /Common/ ) {
      g = H
      sub("\n","",g)
      sub("some","different",g)
      sub("unique","changed",g)
      $0 = g H
   } else { next }
}1'   inputfile

Aqui está o código sed (mostrei na seção Resposta) traduzido em awk .

Observe que o código que você está assumindo está assumindo a responsabilidade de ativar / desativar o sinalizador awk variable para acompanhar as linhas. Mas enquanto, awk já faz isso para você sob o capô exatamente a mesma coisa quando você usa é range operator ,

    
por 18.05.2017 / 06:43
5

Use ex , o editor de arquivos especificado pelo POSIX (e o não-visual forma de vi ).

printf '%s\n' '/This is a unique line' '.,/Common/copy -' %p | ex file.txt

Imprime o conteúdo do arquivo modificado, mas não salva as alterações.

Aqui está o comando para salvar as alterações:

printf '%s\n' '/This is a unique line' '.,/Common/copy -' x | ex file.txt

Ao contrário de Awk e Sed, ex não está limitado a apenas linhas modificadas em ordem. Em vez disso, ele pode operar em todo o buffer em vez de apenas avançar.

O primeiro comando /This is a unique line é apenas um comando de movimento. Move o cursor para a primeira linha do arquivo que possui This is a unique line .

O próximo comando é o comando copy . Ele opera no intervalo de endereços da linha atual ( . ) até a linha seguinte, a partir da correspondência de Common , e copia-os para a linha que precede a linha atual ( - ).

Atualização: para modificação após a cópia, vamos primeiro marcar a linha em que começamos. A primeira linha a ser copiada será marcada com "b" e a linha antes de ser marcada como "a". Então as linhas copiadas serão colocadas entre 'a e b', e podemos usá-las em endereços para nossos comandos "substitutos". E t é sinônimo de copy , a propósito.

printf "/Here is a unique line
kb
-ka
.,/Common/t 'a
'a+,'b-s/unique/changed/g
'a+,'b-s/some/different/g
x
" | ex file.txt
    
por 18.05.2017 / 03:07
5
sed -e '
   /This is a unique line/,/Common/!b
   H
      /Common/!d
   g
      s/^\n//
   h
      s/unique/changed/
      s/some/different/
   G
' yourfile

Explicação

  • Primeiramente, rejeitamos qualquer grupo de linhas sem intervalo.
  • Para cada linha no intervalo, anexamos ao espaço de espera.
  • Vamos apagar todas as linhas lidas até vermos a linha comum. Nesse ponto, recuperamos a área de espera (que deve ter todo o intervalo + um "\ n" principal).
  • Excluímos esta nova linha principal e também atualizamos a retenção. É devido ao comando H BTW.
  • Agora fazemos as edições: exclusivas - > mudou, alguns - > diferente, ...
  • Anexe o espaço de espera (versão inalterada) ao espaço de padrão (versão alterada).
  • sed irá imprimir automaticamente o que está no espaço de padrões.
por 18.05.2017 / 06:25