¿Cómo puedo extraer un rango predeterminado de líneas de un archivo de texto en Unix?

Tengo un volcado de SQL de ~ 23000 líneas que contiene varias bases de datos con valor de datos. Necesito extraer una cierta sección de este archivo (es decir, los datos de una única base de datos) y colocarlo en un nuevo archivo. Conozco los números de línea de inicio y final de los datos que quiero.

¿Alguien conoce un comando Unix (o una serie de comandos) para extraer todas las líneas de un archivo entre las líneas 16224 y 16482 y luego redirigirlas a un nuevo archivo?

sed -n '16224,16482p;16483q' filename > newfile 

Del manual de sed :

p – Imprima el espacio del patrón (a la salida estándar). Este comando por lo general solo se usa junto con la opción de línea de comando -n.

n – Si la autoimpresión no está desactivada, imprima el espacio del patrón, luego, independientemente, reemplace el espacio del patrón con la siguiente línea de entrada. Si no hay más entrada, sed sale sin procesar más comandos.

q – Salir de sed sin procesar más comandos o entradas. Tenga en cuenta que el espacio del patrón actual se imprime si la impresión automática no está desactivada con la opción -n.

y

Las direcciones en un script sed pueden estar en cualquiera de las siguientes formas:

número Especificar un número de línea coincidirá solo con esa línea en la entrada.

Se puede especificar un rango de direcciones especificando dos direcciones separadas por una coma (,). Un rango de direcciones coincide con las líneas que comienzan desde donde coincide la primera dirección, y continúa hasta que la segunda dirección coincida (inclusive).

 sed -n '16224,16482 p' orig-data-file > new-file 

Donde 16224,16482 son el número de línea inicial y el número de línea final, inclusive. Esto es 1-indexado. -n suprime el eco de la entrada como salida, que claramente no desea; los números indican el rango de líneas para que el siguiente comando opere; el comando p imprime las líneas relevantes.

Muy simple usando cabeza / cola:

 head -16482 in.sql | tail -258 > out.sql 

usando sed:

 sed -n '16482,16482p' in.sql > out.sql 

usando awk:

 awk 'NR>=10&&NR<=20' in.sql > out.sql 

Puede usar ‘vi’ y luego el siguiente comando:

 :16224,16482w!/tmp/some-file 

Alternativamente:

 cat file | head -n 16482 | tail -n 258 

EDITAR: – Solo para agregar una explicación, use la cabeza -n 16482 para mostrar las primeras 16482 líneas y luego use la cola -n 258 para obtener las últimas 258 líneas de la primera salida.

Hay otro enfoque con awk :

 awk 'NR==16224, NR==16482' file 

Si el archivo es enorme, puede ser bueno exit después de leer la última línea deseada. De esta forma, no leerá innecesariamente el archivo hasta el final:

 awk 'NR==16224, NR==16482-1; NR==16482 {print; exit}' file 
 perl -ne 'print if 16224..16482' file.txt > new_file.txt 
  # print section of file based on line numbers sed -n '16224 ,16482p' # method 1 sed '16224,16482!d' # method 2 

sed -n '16224,16482p' < dump.sql

 cat dump.txt | head -16224 | tail -258 

debería hacer el truco. La desventaja de este enfoque es que debe hacer la aritmética para determinar el argumento de la cola y explicar si desea que el ‘entre’ incluya la línea final o no.

Rápido y sucio:

 head -16428 < file.in | tail -259 > file.out 

Probablemente no sea la mejor manera de hacerlo, pero debería funcionar.

Por cierto: 259 = 16482-16224 + 1.

Estaba a punto de publicar el truco de cabeza / cola, pero en realidad probablemente acabara de disparar emacs. 😉

  1. escx goto-line ret 16224
  2. mark ( ctrlespacio )
  3. escx goto-line ret 16482
  4. escw

abra el nuevo archivo de salida, ctl-y save

Déjanos ver que esta pasando

Yo usaría:

 awk 'FNR >= 16224 && FNR <= 16482' my_file > extracted.txt 

FNR contiene el número de registro (línea) de la línea que se lee del archivo.

Escribí un progtwig de Haskell llamado splitter que hace exactamente esto: leer la publicación de mi blog de lanzamiento .

Puede usar el progtwig de la siguiente manera:

 $ cat somefile | splitter 16224-16482 

Y eso es todo lo que hay para eso. Necesitarás Haskell para instalarlo. Sólo:

 $ cabal install splitter 

Y has terminado. Espero que este progtwig te sea útil.

Incluso podemos hacer esto para verificar en la línea de comando:

 cat filename|sed 'n1,n2!d' > abc.txt 

Por ejemplo:

 cat foo.pl|sed '100,200!d' > abc.txt 

Usando ruby:

 ruby -ne 'puts "#{$.}: #{$_}" if $. >= 32613500 && $. <= 32614500' < GND.rdf > GND.extract.rdf 

Escribí un pequeño script bash que puedes ejecutar desde tu línea de comando, siempre y cuando actualices tu PATH para incluir su directorio (o puedes colocarlo en un directorio que ya está contenido en la RUTA).

Uso: $ pinch filename start-line end-line

 #!/bin/bash # Display line number ranges of a file to the terminal. # Usage: $ pinch filename start-line end-line # By Evan J. Coon FILENAME=$1 START=$2 END=$3 ERROR="[PINCH ERROR]" # Check that the number of arguments is 3 if [ $# -lt 3 ]; then echo "$ERROR Need three arguments: Filename Start-line End-line" exit 1 fi # Check that the file exists. if [ ! -f "$FILENAME" ]; then echo -e "$ERROR File does not exist. \n\t$FILENAME" exit 1 fi # Check that start-line is not greater than end-line if [ "$START" -gt "$END" ]; then echo -e "$ERROR Start line is greater than End line." exit 1 fi # Check that start-line is positive. if [ "$START" -lt 0 ]; then echo -e "$ERROR Start line is less than 0." exit 1 fi # Check that end-line is positive. if [ "$END" -lt 0 ]; then echo -e "$ERROR End line is less than 0." exit 1 fi NUMOFLINES=$(wc -l < "$FILENAME") # Check that end-line is not greater than the number of lines in the file. if [ "$END" -gt "$NUMOFLINES" ]; then echo -e "$ERROR End line is greater than number of lines in file." exit 1 fi # The distance from the end of the file to end-line ENDDIFF=$(( NUMOFLINES - END )) # For larger files, this will run more quickly. If the distance from the # end of the file to the end-line is less than the distance from the # start of the file to the start-line, then start pinching from the # bottom as opposed to the top. if [ "$START" -lt "$ENDDIFF" ]; then < "$FILENAME" head -n $END | tail -n +$START else < "$FILENAME" tail -n +$START | head -n $(( END-START+1 )) fi # Success exit 0 

Esto podría funcionar para usted (GNU sed):

 sed -ne '16224,16482w newfile' -e '16482q' file 

o aprovechando bash:

 sed -n $'16224,16482w newfile\n16482q' file 

Quería hacer lo mismo desde un script usando una variable y lo logré colocando comillas alrededor de la variable $ para separar el nombre de la variable de la p:

 sed -n "$first","$count"p imagelist.txt >"$imageblock" 

Quería dividir una lista en carpetas separadas y encontré la pregunta inicial y la respuesta un paso útil. (El comando split no es una opción en el viejo OS al que tengo que codificar el puerto).

El -n en las respuestas de aceptación funciona. Aquí hay otra manera en caso de que esté inclinado.

 cat $filename | sed "${linenum}p;d"; 

Esto hace lo siguiente:

  1. canaliza el contenido de un archivo (o introduce el texto como quieras).
  2. sed selecciona la línea dada, la imprime
  3. d es necesario para eliminar líneas; de lo contrario, sed supondrá que todas las líneas se imprimirán finalmente. es decir, sin la d, obtendrá todas las líneas impresas por la línea seleccionada impresas dos veces porque tiene la parte $ {linenum} p pidiendo que se imprima. Estoy bastante seguro de que la -n básicamente está haciendo lo mismo que la d aquí.

Como estamos hablando de extraer líneas de texto de un archivo de texto, daré un caso especial en el que desee extraer todas las líneas que coincidan con un patrón determinado.

 myfile content: ===================== line1 not needed line2 also discarded [Data] first data line second data line ===================== sed -n '/Data/,$p' myfile 

Imprimirá la línea [Datos] y el rest. Si quiere el texto de la línea 1 al patrón, escriba: sed -n ‘1, / Data / p’ myfile. Además, si conoce dos patrones (mejor sea único en su texto), tanto la línea inicial como la final del rango se pueden especificar con coincidencias.

 sed -n '/BEGIN_MARK/,/END_MARK/p' myfile 

Creo que esta podría ser una solución útil. Si el nombre de la tabla es “persona” puede usar sed para obtener todas las líneas que necesita para restaurar su tabla.

 sed -n -e '/DROP TABLE IF EXISTS.*`person `/,/UNLOCK TABLES/p' data.sql > new_data.sql 

En función de esta respuesta , falta la “TABLA DE DEJAR SI EXISTE” para la tabla que está restaurando y debe eliminar algunas líneas de la parte inferior del nuevo archivo antes de usarla para evitar eliminar la siguiente tabla.

La información detallada también se puede encontrar aquí