¿Modificación mediante script "multipaso" de un archivo grande en el lugar (nivel del sistema de archivos)?

¿Modificación mediante script "multipaso" de un archivo grande en el lugar (nivel del sistema de archivos)?

Acabo de llegar al problema de tener que cortar algunas líneas de un archivo de gran tamaño (gigabytes) y, siendo consciente de que un posible consumidor de CPU intentaba leerlo en la memoria, quería editarlo en el lugar... y entonces Me encontré con estas preguntas:

... y además también estos:

Sin embargo, estaba dando vueltas sobre otra cosa: creo (pero no estoy seguro) que cualquier sistema de archivos (como ext3) tendría que emplear algo así como una lista enlazada, para poder describir algo así como fragmentos de un archivo que están asignados a áreas del disco.

Por lo tanto, debería ser posible hacer algo como esto; por ejemplo, digamos que tengo un archivo bigfile.datcomo este (los números deben indicar el desplazamiento de bytes, pero es un poco difícil alinearlos):

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

L 1\n L 2\n L 3\n L 4\n L 5\n L 6\n

Este archivo podría, en principio, cargarse en una aplicación de terminal para navegar; imaginemos que llamamos a una herramienta editsegments bigfile.daty digámoslo de manera similar a como less -N bigfile.datse mostraría el mismo archivo (con números de línea):

      1      1      L 1
      2      2      L 2 *
      3      3      L 3
      4      4      L 4 *
      5      5      L 5
      6      6      L 6
bigfile.dat (END) 

Digamos que podría ingresar un comando allí (por ejemplo, dpara eliminar líneas), hacer clic en otra tecla o con el mouse donde se indica arriba con *, lo que significa que todo lo que se encuentra entre las líneas 2 y 4 debe eliminarse. El programa entonces respondería mostrando esto:

      1      1      L 1
      2      5      L 5
      3      6      L 6
bigfile.dat (END) 

Ahora podemos ver que la primera columna situada más a la izquierda muestra el número de línea "nuevo" (después del corte), la segunda columna es el número de línea "antiguo" (antes del corte), y luego sigue el contenido de la línea real.

Ahora, lo que imagino que sucede después de editsegmentssalir de esta pseudoaplicación es que, ante todo, bigfile.datpermanece intacta; sin embargo, ahora también habrá un archivo de texto adicional en el mismo directorio, por ejemplo bigfile.dat.segments; con estos contenidos:

d 4:15 # line 2-4

bigfile.dat.iedit... y además, aparecería un archivo especial (como un "enlace simbólico"), llamémoslo .

Ahora, básicamente, el resultado de todo esto sería que si intento abrir bigfile.dat.ieditcon algo como less -N bigfile.dat.iedit, querría obtener el contenido "editado":

      1 L 1
      2 L 5
      3 L 6
bigfile.dat (END) 

... lo que podría lograrse, supongo, instruyendo de alguna manera al sistema operativo, que cuando $FILE.ieditse abre, primero $FILE.segmentsse debe abrir y leer; Esto d 4:15indicaría que se deben omitir los bytes 4 a 15 del archivo original, lo que daría como resultado algo como:

0 1 2 3 4 5 6 7 8 9 10 11 12,3,4 15 16 17 18 19 20 21 22 23

L 1\n L2\n L3\n L4\n L 5\n L 6\n

0 1 2 3 ------------------------------->16 17 18 19 20 21 22 23

En otras palabras -asumiendoque en un concepto de sistema de archivos de un archivo, cada byte de contenido también contiene un "enlace" al siguiente byte en la cadena; debería ser posible indicarle al sistema de archivos que establezca una nueva lista enlazada basada en un script y proporcione el contenido como lo representa esta lista enlazada modificada a través de un archivo especial (enlace simbólico o canalización).

Eso es lo que quise decir con "scripted" en el título: que la "nueva" lista enlazada puede controlarse mediante un archivo de script ( $FILE.segments), editable por el usuario en un editor de texto (o generado por una aplicación de interfaz). Lo que quise decir con “multipass” es el hecho de que bigfile.daten este proceso no se modifica en absoluto; así que podría editar el primer gigabyte (original) hoy, guardando el progreso en ( $FILE.segments) - luego podría editar el segundo gigabyte mañana, guardando nuevamente el progreso en ( $FILE.segments), etc. - mientras tanto, el original bigfile.datno cambia.

Cuando se completen todas las ediciones, probablemente se podría llamar una especie de comando (por ejemplo, editsegments --finalize bigfile.dat), que simplemente codificaría permanentemente la nueva lista vinculada como el contenido de bigfile.dat(y en línea con eso, eliminaría bigfile.dat.segmentsy bigfile.dat.iedit). O incluso más fácil, uno podría simplemente hacer:

cp bigfile.dat.iedit /path/to/somewhere/else/bigfile.modified.dat

Por supuesto, además del dcomando eliminar script, rtambién se podría tener un comando eplace, por ejemplo:

r 16:18 AAA 

... diciendo: reemplace el contenido entre los bytes 16 y 18 con los siguientes 18-16+1=3 bytes después del espacio (es decir, el AAA); de hecho, la lista vinculada podría "engancharse" al contenido del comando del script ( el cuadro a continuación que contiene también el delete):

0 1 2 3 4 5 6 7 8 9 10 11 12,3,4 15 16 17 18 19 20 21 22 23

L 1\n L2\n L3\n L4\n L 5\n L 6\n

0 1 2 3 ------------------------------->| | 19 20 21 22 23

. . ...\n r1  6  :18  AAA \n  . .  . .


Ahora, supongo que programas como hexedit(como se mencionóaquí) cambian los archivos in situ, pero me gustaría tener el beneficio de la posibilidad de crear secuencias de comandos (aún mejor si pudiera regularse mediante una aplicación GUI, incluso si es una terminal), y el beneficio de no tener realmente el archivo original. modificado, hasta que se confirme que todas las ediciones son según lo requerido.

No estoy seguro de si algo como esto es posible en absoluto - e incluso si lo es, supongo que puede requerir un controlador dedicado (en lugar de sólo un programa de usuario)... Pero supongo que vale la pena preguntar de todos modos - ¿existe? ¿Algo como esto para Linux?

Muchas gracias de antemano por cualquier respuesta,
¡Saludos!

Respuesta1

La estructura de los archivos en el disco depende del sistema de archivos utilizado. Ninguno de los sistemas de archivos del mundo real utiliza listas vinculadas como usted describe (eso sería fseek(3)insoportable). Lo más parecido a esto es el de Microsoft.GORDO, esencialmente moviendo los punteros fuera de los bloques de datos a una matriz que los sigue.

Pero la mayoría de los sistemas de archivos utilizan algunas referencias basadas en punteros a bloques de datos en el archivo, por lo que, en principio, se podría cortar un bloque de un archivo simplemente mezclando un puñado de punteros (no todo el contenido del archivo) y marcando un bloque en el archivo. medio del archivo como gratuito. Lamentablemente, esta no es una operación muy útil, los bloques de archivos son bastante grandes (normalmente 4 KB) y rara vez se alinean razonablemente con las estructuras del archivo (ya sean líneas u otras subdivisiones).

Respuesta2

Lo que usted describe suena mucho arepeticiónde un editor de textolista de rehacercontra el archivo original sin cambios al que selista de rehacerpertenece. Estoy bastante seguro de que gvimtiene talpersistenteLista de deshacer/rehacer, que usted puede (?) utilizar, y sé que emacsdefinitivamente tiene una lista de este tipo a la que probablemente podría convencer para que haga lo que quiera (a través de un elispscript), por ejemplo.Guardar el historial de deshacer de Emacs entre sesiones.

Como nota al margen, desactivar todas las acciones no deseadas podría ser una buena idea para archivos tan grandes, por ejemplo:guardado automático,resaltado de sintaxis(lento en ungrandearchivo emacs), etc. y emacs en un sistema de 32 bits tiene 256 MBlímite de tamaño de archivo.

Ciertamente no será tan conciso como lo que sugirió, pero puede ser útil si no hay una gran cantidad de cambios.

Respuesta3

Generalmente, no se puede editar un archivo en el lugar sin guardarlo completo en la memoria. Supongo que lo que realmente quieres hacer es tener un archivo nuevo que sea una copia del anterior sin líneas específicas. Esto se puede lograr fácilmente usando las utilidades de Unix heady tail. Por ejemplo, para copiar todo excepto las líneas 5, 12 y 52 de un archivo, puede hacer

head -n 4 bigfile.dat > tempfile.dat
tail -n +6 bigfile.dat | head -n 6 >> tempfile.dat 
tail -n +13 bigfile.dat | head -n 39 >> tempfile.dat 
tail -n 53 bigfile.dat >> tempfile.dat

En caso de que no estés familiarizado con estas utilidades, te las explicaré con más detalle.

La headutilidad imprime las primeras n líneas de un archivo. Si no se le proporciona un argumento posicional, utilizará la entrada estándar como archivo. La -nbandera le indica al cabezal cuántas líneas imprimir. Entonces, head -n 2imprimirá solo las primeras 2 líneas de la entrada estándar.

La tailutilidad imprime las últimas n líneas de un archivo. Al igual que head, puede leer desde un archivo o una entrada estándar. La bandera -n le dice a tail cuántas líneas imprimir desde el final. También puede anteponer el número con un signo más para indicarle a tail que imprima las líneas desde el final del archivo comenzando con esa cantidad de líneas desde el principio. Por ejemplo, tail -n 2imprime las dos últimas líneas de la entrada estándar. Sin embargo, tail -n +2imprime todas las líneas que comienzan con la línea número 2 (omite la línea 1).

Entonces, en general, si desea imprimir líneas en el rango [x, y) de un archivo, haría

`tail -n +x | head -n d`

donde d = y - x. Estos comandos producirán un nuevo archivo. Luego puede eliminar el archivo antiguo si lo desea. La ventaja de hacerlo de esta manera es que headsolo tailnecesita mantener una línea en la memoria a la vez, por lo que no llenará rápidamente su RAM.

Respuesta4

Suena como un trabajo para un guión sed. IIRC fue diseñado para tales tareas. El procesamiento línea por línea, el procesamiento repetido del mismo grupo de comandos y las expresiones regulares se combinan en una sola herramienta. Si bien sé que funcionará, no puedo guiarlo más que dirigirlo a su excelentepágina de manual.

información relacionada