Selecionando uma seção de um arquivo

Selecionando uma seção de um arquivo

Eu tenho um arquivo formatado assim:

title1
        line
        line

title2
        line
        line

        line

title3
        line
        line

e gostaria de extrair a seção abaixo title2e remover o recuo. Atualmente estou usando sed(mas awkou um script de shell seria adequado no meu contexto, infelizmente não em linguagens como perlou python) assim:

sed -n -e '/^title2$/,/^[a-zA-Z]/ { /^[a-zA-Z]/ d ; s/^[ \t]*// ; p }'

mas isso deixa uma linha logicamente em branco no final (logicamente porque pode ter espaços em branco ou tabulações). Eu quero me livrar disso. Observe que pode haver outras linhas logicamente em branco na parte a serem mantidas (ou /^[ \t]*$/ dteria feito o trabalho). Assim, eu gostaria deste resultado:

line
line

line

Posso fazer com um adicional sed -e '$d'mas gostaria de saber se é possível evitar esse segundo processo.

Responder1

Usei o espaço de espera e acabei com

sed -ne '/^title2$/,/^[a-zA-Z]/ { /^title2$/ { n; h; b; } ; /^[a-zA-Z]/ d; H; x; s/[ \t]*//; P; s/.*\n//; x }'

que parece lidar corretamente com os casos que me interessam.

Responder2

  • se for uma linha "pura" (sem tabulação ou branca), exclua-a também com/^$/
  • para uso em branco "lógico"/^\s*$/

    sed -n -e '/^title2:/,/^[a-zA-Z]/ { /^[a-zA-Z]/ d ; /^$/ d ; s/^[ \t]*// ; p }' 
    

onde

  • /^$/combinar linha inicial, fim da linha
  • /^\s*$/corresponde à linha inicial, zero ou mais espaço ou tabulação, fim da linha

Responder3

sed -n '/title2/,/^\S/ { //b; /^\s*$/ { N; /\n\S/q; P; D }; s/^\s*//; p }'

Inicialmente fiz isso para chamar a atenção de @Archemar. Eu realmente apreciaria se você pudessepor favorresponder ameu comentário neste postquando você tiver tempo. Mesmo que a resposta seja “não sei”. OBRIGADO.

No meu shell bash, pelo menos, funciona sem o -e. Apenas curioso para saber por que isso é necessário? E se\sou\Snão é suportado, você pode substituí-los por [ \t]'s' e [^ \t]'s, respectivamente.

Repartição para pessoas que eram tão ignorantes quanto eu quando vi esta pergunta pela primeira vez:

  • -ndesativa a impressão automática
  • /title2/,/^\S/é um intervalo para sedpesquisar (da linha da primeira ocorrência da string, " title2" até a próxima linha que começa com um caractere que não seja espaço [ou seja title3]inclusivamente)
  • {significa apenas aplicar os comandos incluídos ao intervalo ou padrão que acabei de especificar
    • //bpermite que os seguintes comandos não se apliquem ao início e ao fim do intervalo.
      Mais literalmente, se você combinar title2ou ^\Sapenas ramificar para o final do script( b)(processar a próxima linha no arquivo, se sobrar alguma) porque emGNUsed(BSDdiz o mesmo, não tenho certeza se existe alguma outra versão de sed)

      '//' repete a última correspondência de expressão regular

    • /^\s*$/corresponde às linhas "logicamente em branco" no intervalo.
    • {
      • N; /\n\S/q;Portanto, se for uma linha "logicamente em branco", Nadicionar a próxima linha ao espaço do padrão e, se a próxima linha for o próximo título, ela encerrará o processamento completamente ( q), portanto, nem a linha "logicamente em branco" nem o próximo título serão impresso.
      • P; DSe a linha "logicamente em branco"não éseguido pelo próximo título, entãoapenasa linha "logicamente em branco" é impressa ( P) e entãoapenasa linha "logicamente em branco" é excluída do espaço padrão, deixando a próxima linha que foi adicionada ao espaço padrão para Nser processada desde o início do script ( D)
    • }
    • s/^\s*//; ptira os espaços e tabulações no início da linha e imprime a linha formatada
  • }

@Archemar por favorAJUDA

informação relacionada