Eu tenho um arquivo formatado assim:
title1
line
line
title2
line
line
line
title3
line
line
e gostaria de extrair a seção abaixo title2
e remover o recuo. Atualmente estou usando sed
(mas awk
ou um script de shell seria adequado no meu contexto, infelizmente não em linguagens como perl
ou 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]*$/ d
teria 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\s
ou\S
nã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:
-n
desativa a impressão automática/title2/,/^\S/
é um intervalo parased
pesquisar (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 sejatitle3
]inclusivamente){
significa apenas aplicar os comandos incluídos ao intervalo ou padrão que acabei de especificar//b
permite que os seguintes comandos não se apliquem ao início e ao fim do intervalo.
Mais literalmente, se você combinartitle2
ou^\S
apenas 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 desed
)'//' 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",N
adicionar 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; D
Se 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 paraN
ser processada desde o início do script (D
)
}
s/^\s*//; p
tira os espaços e tabulações no início da linha e imprime a linha formatada
}
@Archemar por favorAJUDA