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


Tengo un volcado SQL de ~23000 líneas que contiene varias bases de datos de datos. Necesito extraer una cierta sección de este archivo (es decir, los datos de una sola base de datos) y colóquelo en un nuevo archivo. Sé 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, por ejemplo, la línea 16224 y 16482 y luego redirigirlas a un nuevo archivo?

Author: lesmana, 2008-09-17

21 answers

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

Del manual del sed :

P - Imprima el espacio del patrón (a la salida estándar). Este comando generalmente solo se usa junto con la opción de línea de comandos-n.

N - Si la impresión automática no está desactivada, imprima el espacio del patrón y, de todos modos, reemplace el espacio del patrón con la siguiente línea de entrada. Si no hay más entrada, entonces sed sale sin procesar más comando.

Q - Exit sed sin procesar más comandos o entradas. Tenga en cuenta que el espacio de 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 separados por una coma (,). Un rango de direcciones partidos líneas a partir de donde la primera dirección coincide, y continúa hasta la segunda coincidencias de direcciones (inclusivas).

 635
Author: boxxar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-13 18:09:58
sed -n '16224,16482 p' orig-data-file > new-file

Donde 16224,16482 son el número de línea de inicio y el número de línea de final, ambos 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 hacer que el siguiente comando opere; el comando p imprime las líneas relevantes.

 184
Author: JXG,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-10-19 10:55:41

Bastante simple usando head / tail:

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
 73
Author: manveru,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-17 13:46:05

Puedes 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, usa head-n 16482 para mostrar las primeras 16482 líneas y luego usa tail-n 258 para obtener las últimas 258 líneas de la primera salida.

 23
Author: Mark Janssen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-16 20:37:10

Hay otro enfoque con awk:

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

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

awk 'NR==16224, NR==16482-1; NR==16482 {print; exit}' file
 19
Author: fedorqui,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-15 09:29:40
perl -ne 'print if 16224..16482' file.txt > new_file.txt
 13
Author: mmaibaum,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-05 18:38:10
 # print section of file based on line numbers
 sed -n '16224 ,16482p'               # method 1
 sed '16224,16482!d'                 # method 2
 7
Author: Cetra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-17 13:42:38

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

 5
Author: cubex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-17 13:45:18
cat dump.txt | head -16224 | tail -258

Debería hacer el truco. La desventaja de este enfoque es que necesita hacer la aritmética para determinar el argumento para la cola y para tener en cuenta si desea que el 'entre' incluya la línea final o no.

 5
Author: JP Lodine,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-05 18:39:48

Rápido y sucio:

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

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

BTW: 259 = 16482-16224+1.

 3
Author: jan.vdbergh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-17 13:44:24

Estaba a punto de publicar el truco de cabeza/cola, pero en realidad probablemente solo encendería emacs. ;-)

  1. esc-x goto-line ret 16224
  2. marca (ctrl-espacio)
  3. esc-x goto-line ret 16482
  4. esc-w

Abra el nuevo archivo de salida, ctl-y guardar

Veamos qué está pasando.

 2
Author: sammyo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-26 15:40:09

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.

 2
Author: Paddy3118,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-01 18:51:30

Escribí un programa de Haskell llamado splitterque hace exactamente esto: tener un leer a través de mi publicación de blog de liberación.

Puede utilizar el programa de la siguiente manera:

$ cat somefile | splitter 16224-16482

Y eso es todo lo que hay en ello. Necesitarás Haskell para instalarlo. Solo:

$ cabal install splitter

Y has terminado. Espero que encuentre útil este programa.

 2
Author: Robert Massaioli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-25 22:43:32

Incluso podemos hacer esto para comprobar en la línea de comandos:

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

Por Ejemplo:

cat foo.pl|sed '100,200!d' > abc.txt
 2
Author: Chinmoy Padhi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-05 07:02:03

Usando ruby:

ruby -ne 'puts "#{$.}: #{$_}" if $. >= 32613500 && $. <= 32614500' < GND.rdf > GND.extract.rdf
 2
Author: Carl Blakeley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-21 12:23:02

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

Uso: pinch 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
 1
Author: Nerdfighter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-10 17:06:47

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
 1
Author: potong,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-10 13:00:01

Quería hacer lo mismo desde un script usando una variable y lo logré poniendo 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 antiguo sistema operativo al que tengo que portar el código).

 1
Author: KevinY,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-28 09:35:10

El-n en aceptar respuestas funciona. Aquí hay otra manera en caso de que te inclines.

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

Esto hace lo siguiente:

  1. pipe en el contenido de un archivo (o feed en el texto como quieras).
  2. sed selecciona la línea dada, la imprime
  3. se requiere d para eliminar líneas, de lo contrario sed asumirá que todas las líneas finalmente se imprimirán. 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 el-n está haciendo básicamente lo mismo que el d aquí.
 0
Author: ThinkBonobo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-07 18:52:53

Dado que estamos hablando de extraer líneas de texto de un archivo de texto, daré un caso especial donde desea extraer todas las líneas que coincidan con un cierto patrón.

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

Imprimirá la línea [Data] y el resto. Si desea el texto de la línea 1 al patrón, escriba: sed-n '1,/Data / p' myfile. Además, si conoce dos patrones (es mejor que 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
 0
Author: Kemin Zhou,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-14 22:52:13

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

Basado en esta respuesta, donde le falta la "DROP TABLE IF EXIST" para la tabla que está restaurando y necesita eliminar algunas líneas de la parte inferior del nuevo archivo antes de usarlo para evitar eliminar la siguiente tabla.

También se puede encontrar información detallada aquí

 -3
Author: dvergur,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:02:48