Tengo un archivo formateado como este:
title1
line
line
title2
line
line
line
title3
line
line
y me gustaría extraer la sección siguiente title2
y eliminar la sangría. Actualmente estoy usando sed
(pero awk
o un script de shell sería adecuado en mi contexto, lamentablemente no lenguajes como perl
o python
) como este:
sed -n -e '/^title2$/,/^[a-zA-Z]/ { /^[a-zA-Z]/ d ; s/^[ \t]*// ; p }'
pero eso deja una línea lógicamente en blanco al final (lógicamente porque puede tener espacios en blanco o pestañas). Quiero deshacerme de eso. Tenga en cuenta que puede haber otras líneas lógicamente en blanco en la parte a conservar (o /^[ \t]*$/ d
habría hecho el trabajo). Por eso me gustaría este resultado:
line
line
line
Puedo hacerlo con un adicional sed -e '$d'
pero me gustaría saber si es posible evitar ese segundo proceso.
Respuesta1
Usé el espacio de espera y terminé con
sed -ne '/^title2$/,/^[a-zA-Z]/ { /^title2$/ { n; h; b; } ; /^[a-zA-Z]/ d; H; x; s/[ \t]*//; P; s/.*\n//; x }'
que parece manejar correctamente los casos que me ocupan.
Respuesta2
- si es una línea "pura" (sin tabulación o blanca), bórrala también con
/^$/
para uso en blanco "lógico"
/^\s*$/
sed -n -e '/^title2:/,/^[a-zA-Z]/ { /^[a-zA-Z]/ d ; /^$/ d ; s/^[ \t]*// ; p }'
dónde
/^$/
coincidir con la línea de inicio, el final de la línea/^\s*$/
coincidir con la línea de inicio, cero o más espacios o tabulaciones, final de línea
Respuesta3
sed -n '/title2/,/^\S/ { //b; /^\s*$/ { N; /\n\S/q; P; D }; s/^\s*//; p }'
Inicialmente hice esto para llamar la atención de @Archemar. Realmente te agradecería si pudieraspor favorresponder ami comentario en este postcuando tengas tiempo. Incluso si la respuesta es "no lo sé". GRACIAS.
En mi shell bash, al menos, funciona sin -e
. ¿Solo tengo curiosidad por saber por qué es necesario? Y si\s
o\S
no es compatible, puede reemplazarlos con [ \t]
's y [^ \t]
's, respectivamente.
Desglose de personas que no tenían ni idea como yo cuando vi esta pregunta por primera vez:
-n
desactiva la impresión automática/title2/,/^\S/
es un rango parased
buscar (desde la línea de la primera aparición de la cadena, "title2
" hasta la siguiente línea que comienza con un carácter que no sea un espacio [es decirtitle3
]inclusive){
solo significa aplicar los comandos adjuntos al rango o patrón que acabo de especificar//b
permite que los siguientes comandos no se apliquen al inicio y al final del rango.
Más literalmente, si coincidetitle2
o^\S
simplemente se ramifica hasta el final del script (b
) (procesa la siguiente línea del archivo, si queda alguna) porque enÑUsed
(BSDdice lo mismo, no estoy seguro si hay alguna otra versión desed
)'//' repite la última coincidencia de expresión regular
/^\s*$/
coincide con las líneas "lógicamente en blanco" del rango.{
N; /\n\S/q;
Entonces, si es una línea "lógicamente en blanco",N
agrega la siguiente línea al espacio del patrón y luego, si esa siguiente línea es el siguiente título, deja de procesarse por completo (q
), por lo que ni la línea "lógicamente en blanco" ni el siguiente título son impreso.P; D
Si la línea "lógicamente en blanco"no esseguido del siguiente título, luegojustose imprime la línea "lógicamente en blanco" (P
), y luegojustola línea "lógicamente en blanco" se elimina del espacio del patrón, dejando que la siguiente línea que se agregó al espacio del patrón seN
procese desde el principio del script (D
)
}
s/^\s*//; p
elimina los espacios y tabulaciones al principio de la línea e imprime la línea formateada
}
@Archemar por favorAYUDA