Seleccionar una sección de un archivo

Seleccionar una sección de un archivo

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 title2y eliminar la sangría. Actualmente estoy usando sed(pero awko un script de shell sería adecuado en mi contexto, lamentablemente no lenguajes como perlo 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]*$/ dhabrí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\so\Sno 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:

  • -ndesactiva la impresión automática
  • /title2/,/^\S/es un rango para sedbuscar (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 decir title3]inclusive)
  • {solo significa aplicar los comandos adjuntos al rango o patrón que acabo de especificar
    • //bpermite que los siguientes comandos no se apliquen al inicio y al final del rango.
      Más literalmente, si coincide title2o ^\Ssimplemente 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 de sed)

      '//' 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", Nagrega 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; DSi 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 se Nprocese desde el principio del script ( D)
    • }
    • s/^\s*//; pelimina los espacios y tabulaciones al principio de la línea e imprime la línea formateada
  • }

@Archemar por favorAYUDA

información relacionada