¿Cómo puedo eliminar la primera línea de un archivo de texto usando script bash / sed?

Necesito eliminar repetidamente la primera línea de un gran archivo de texto usando un script bash.

En este momento estoy usando sed -i -e "1d" $FILE – pero toma alrededor de un minuto realizar la eliminación.

¿Hay una manera más eficiente de lograr esto?

Pruebe la cola de GNU :

 tail -n +2 "$FILE" 

-nx : Simplemente imprime las últimas x líneas. tail -n 5 te daría las últimas 5 líneas de la entrada. El signo + invierte el argumento y hace que la tail imprima algo excepto las primeras líneas x-1 . tail -n +1 imprimiría todo el archivo, tail -n +2 todo menos la primera línea, etc.

La tail GNU es mucho más rápida que sed . tail también está disponible en BSD y la bandera -n +2 es consistente en ambas herramientas. Consulte las páginas man de FreeBSD u OS X para obtener más información.

La versión de BSD puede ser mucho más lenta que sed . Me pregunto cómo lo lograron; tail solo debe leer un archivo línea por línea, mientras que sed realiza operaciones bastante complejas que implican interpretar un script, aplicar expresiones regulares y cosas por el estilo.

Nota: puede estar tentado de usar

 # THIS WILL GIVE YOU AN EMPTY FILE! tail -n +2 "$FILE" > "$FILE" 

pero esto te dará un archivo vacío . La razón es que la redirección ( > ) ocurre antes de que el intérprete de comandos invoque la tail :

  1. Shell trunca el archivo $FILE
  2. Shell crea un nuevo proceso para la tail
  3. Shell redirige la salida estándar del proceso de tail a $FILE
  4. tail lee desde el $FILE ahora vacío

Si desea eliminar la primera línea dentro del archivo, debe usar:

 tail -n +2 "$FILE" > "$FILE.tmp" && mv "$FILE.tmp" "$FILE" 

El && se asegurará de que el archivo no se sobrescriba cuando hay un problema.

Puede usar -i para actualizar el archivo sin usar el operador ‘>’. El siguiente comando eliminará la primera línea del archivo y lo guardará en el archivo.

 sed -i '1d' filename 

Para aquellos que están en SunOS que no es GNU, el siguiente código ayudará:

 sed '1d' test.dat > tmp.dat 

No, es tan eficiente como lo que obtendrás. Podría escribir un progtwig en C que podría hacer el trabajo un poco más rápido (menos tiempo de inicio y argumentos de procesamiento) pero probablemente tenderá a la misma velocidad que sed a medida que los archivos se agranden (y supongo que son grandes si tarda un minuto )

Pero su pregunta sufre el mismo problema que muchos otros ya que presupone la solución. Si nos diera en detalle lo que está tratando de hacer en lugar de cómo , podemos sugerir una mejor opción.

Por ejemplo, si este es un archivo A que procesa algún otro progtwig B, una solución sería no quitar la primera línea, sino modificar el progtwig B para procesarla de manera diferente.

Digamos que todos sus progtwigs se agregan a este archivo A y el progtwig B actualmente lee y procesa la primera línea antes de eliminarla.

Puede rediseñar el progtwig B para que no intente eliminar la primera línea, pero mantiene una compensación persistente (probablemente basada en archivos) en el archivo A para que, la próxima vez que se ejecute, pueda buscar ese desplazamiento, proceso la línea allí, y actualizar el desplazamiento.

Entonces, en un momento de silencio (¿medianoche?), Podría hacer un procesamiento especial del archivo A para eliminar todas las líneas procesadas actualmente y establecer el desplazamiento de nuevo en 0.

Ciertamente será más rápido para un progtwig abrir y buscar un archivo en lugar de abrir y reescribir. Esta discusión asume que tienes control sobre el progtwig B, por supuesto. No sé si ese es el caso, pero puede haber otras soluciones posibles si proporciona más información.

Puede editar los archivos en su lugar: simplemente use el indicador -i de perl, así:

 perl -ni -e 'print unless $. == 1' filename.txt 

Esto hace que la primera línea desaparezca, como preguntas. Perl necesitará leer y copiar el archivo completo, pero arregla para que la salida se guarde con el nombre del archivo original.

Como dijo Pax, probablemente no vas a obtener nada más rápido que esto. La razón es que casi no hay sistemas de archivos que admitan truncar desde el principio del archivo, por lo que esta será una operación O ( n ) donde n es el tamaño del archivo. Sin embargo, lo que puede hacer mucho más rápido es sobrescribir la primera línea con el mismo número de bytes (tal vez con espacios o un comentario) que podría funcionar para usted dependiendo de exactamente lo que está tratando de hacer (¿qué es eso por cierto?).

La herramienta de sponge evita la necesidad de hacer malabares con un archivo temporal:

 tail -n +2 "$FILE" | sponge "$FILE" 

debe mostrar las líneas excepto la primera línea:

 cat textfile.txt | tail -n +2 

¿Qué hay de usar csplit?

 man csplit csplit -k file 1 '{1}' 

Podría usar vim para hacer esto:

 vim -u NONE +'1d' +'wq!' /tmp/test.txt 

Esto debería ser más rápido, ya que vim no leerá el archivo completo durante el proceso.

Si desea modificar el archivo en su lugar, siempre puede utilizar el ed original en lugar de su siguiente sed :

 ed "$FILE" <<<$'1d\nwq\n' 

Como parece que no puedo acelerar la eliminación, creo que un buen enfoque podría ser procesar el archivo en lotes como este:

 While file1 not empty file2 = head -n1000 file1 process file2 sed -i -e "1000d" file1 end 

El inconveniente de esto es que si el progtwig se mata en el medio (o si hay algún sql malo allí – causando que la parte del “proceso” muera o se bloquee), habrá líneas que se omiten o se procesan dos veces .

(archivo1 contiene líneas de código sql)

Si lo que estás buscando hacer es recuperarte después de la falla, puedes crear un archivo que tenga lo que has hecho hasta ahora.

 if [[ -f $tmpf ]] ; then rm -f $tmpf fi cat $srcf | while read line ; do # process line echo "$line" >> $tmpf done 

¿Haría el trabajo usando cola en líneas N-1 y dirigiendo eso en un archivo, seguido de eliminar el archivo anterior y renombrando el nuevo archivo con el nombre anterior?

Si estuviese haciendo esto programáticamente, leería el archivo y recordaría el desplazamiento del archivo, después de leer cada línea, así podría volver a esa posición para leer el archivo con una línea menos.