extraer líneas de texto de un archivo largo

extraer líneas de texto de un archivo largo

Tengo el siguiente archivo de texto:

#unimportant comment
#possible more unimportant comments
#info1 info2 info3 ,importantname1
importanttext1
#info1 info2 info3 ,importantname2
importanttext2
#info1 info2 info3 ,importantname3
importanttext3

Quiero dividir cada archivo en archivos separados. Todo lo que realmente necesito es extraer las URL no comentadas; conservar los comentarios es opcional. Quiero que cada archivo tenga un nombre como importantname1.txt o el nombre que sigue a la coma al final de cada línea de comentario junto con .txt.

tan importantenombre1.txt tendría el siguiente contenido:

importanttext1 

o posiblemente

#info1 info2 info3 ,importantname1
importanttext1

por lo que la línea se extraerá y guardará con el nombre del archivo después del comentario y se agregará con .txt, en este caso nombre de archivo importantenombre1.txt

Necesito hacer esto para cada conjunto de líneas en el archivo de ejemplo. Preservar los comentarios no es importante, pero necesito que sea compatible con secuencias de comandos. También necesito tener en cuenta un número desconocido de líneas de comentarios en el encabezado. La línea de comentario siempre estará ahí antes de cada línea de texto importanteX.

Respuesta1

Intentar:

awk -F, '/^#/{f=$NF".txt";cmt=$0; next} {printf "%s\n%s\n",cmt,$0 >f; close(f)}' file

Ejemplo

Aplicado a su entrada de muestra:

$ awk -F, '/^#/{f=$NF".txt";cmt=$0; next} {printf "%s\n%s\n",cmt,$0 >f; close(f)}' file

Después de ejecutar lo anterior, los siguientes archivos están en el directorio:

$ ls
file  importantname1.txt  importantname2.txt  importantname3.txt

El contenido de los nuevos archivos es:

$ cat importantname1.txt 
#info1 info2 info3 ,importantname1
importanttext1
$ cat importantname2.txt 
#info1 info2 info3 ,importantname2
importanttext2
$ cat importantname3.txt 
#info1 info2 info3 ,importantname3
importanttext3

Cómo funciona

Awk lee el archivo de entrada línea por línea. Nuestro script clasifica esas líneas como comentarios o no comentarios. Para las líneas de comentarios, se guarda el nombre del archivo y el comentario. Para los que no tienen comentarios, se crea e imprime un nuevo archivo.

  • `-F,

    Esto le dice a awk que use una coma como separador de campo en la entrada. De esta forma, el nombre del archivo siempre será el último campo.

  • /^#/{f=$NF".txt";cmt=$0; next}

    Si una línea comienza con #, guardamos el último campo $NFy además .txtcomo nombre de archivo f. Toda la línea de comentario se guarda como cmt. Luego le decimos a awk que omita el resto de los comandos y salte para comenzar de nuevo en la nextlínea.

  • printf "%s\n%s\n",cmt,$0 >f; close(f)

    Para las líneas que no son comentarios, imprimimos el último comentario visto, cmty la línea actual, $0en el último nombre del archivo visto f. Luego cerramos el identificador del archivo para f.

Protección contra nombres de archivos incorrectos

Si los campos que se van a utilizar como nombres de archivos contienen /, el sistema operativo interpretará que los nombres de los archivos incluyen directorios. Para evitar eso, podemos reemplazar all /con el siguiente -uso :gsub(/\//, "-", f)

awk -F, '/^#/{f=$NF".txt";gsub(/\//, "-", f); cmt=$0; next} {printf "%s\n%s\n",cmt,$0 >f; close(f)}' file

Respuesta2

Una combinación de grepy csplitpodría hacer el trabajo, a) grephaciendo ping a todas las líneas no comentadas más la información anterior y b) dividiendo la salida según la línea de comentario de información:

grep -v -B1 '^#' file | csplit -z - '/^#/' '{*}'

Es decir, no -vextraiga líneas que tengan un # al principio ^#sino una línea que las preceda -B1. Luego divida la entrada canalizada entrante -en cada # al comienzo de una línea, ignore los archivos vacíos -zy hágalo con la mayor frecuencia posible {*}.

Cambiar el nombre tendría que ser un paso separado ( csplitautonombra la salida como xx00, xx01... - cambia el pre y el sufijo con las opciones -fy -b, respectivamente)

#/bin/bash
for f in xx* ; do
   mv "$f" "$( sed -n '2p' "$f" )".txt
done

información relacionada