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$NF
y además.txt
como nombre de archivof
. Toda la línea de comentario se guarda comocmt
. Luego le decimos a awk que omita el resto de los comandos y salte para comenzar de nuevo en lanext
línea.printf "%s\n%s\n",cmt,$0 >f; close(f)
Para las líneas que no son comentarios, imprimimos el último comentario visto,
cmt
y la línea actual,$0
en el último nombre del archivo vistof
. Luego cerramos el identificador del archivo paraf
.
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 grep
y csplit
podría hacer el trabajo, a) grep
haciendo 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 -v
extraiga 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 -z
y hágalo con la mayor frecuencia posible {*}
.
Cambiar el nombre tendría que ser un paso separado ( csplit
autonombra la salida como xx00, xx01... - cambia el pre y el sufijo con las opciones -f
y -b
, respectivamente)
#/bin/bash
for f in xx* ; do
mv "$f" "$( sed -n '2p' "$f" )".txt
done