Necesito eliminar repetidamente la primera línea de un gran archivo de texto usando un script bash.
En este momento lo estoy usando sed -i -e "1d" $FILE
, pero me lleva alrededor de un minuto eliminarlo.
¿Hay una manera más eficiente de lograr esto?
Respuestas:
Prueba la cola :
-n x
: Solo imprime las últimasx
líneas.tail -n 5
le daría las últimas 5 líneas de la entrada. El+
tipo de signo invierte el argumento y hacetail
imprimir cualquier cosa menos las primerasx-1
líneas.tail -n +1
imprimiría todo el archivo,tail -n +2
todo menos la primera línea, etc.GNU
tail
es mucho más rápido quesed
.tail
también está disponible en BSD y el-n +2
indicador es coherente en ambas herramientas. Consulte las páginas de manual de FreeBSD o OS X para obtener más información.Sin
sed
embargo, la versión BSD puede ser mucho más lenta que . Me pregunto cómo lograron eso;tail
debería leer un archivo línea por línea mientrassed
realiza operaciones bastante complejas que implican interpretar un script, aplicar expresiones regulares y similares.Nota: es posible que tengas la tentación de usar
pero esto te dará un archivo vacío . La razón es que la redirección (
>
) ocurre antestail
de que el shell la invoque:$FILE
tail
tail
proceso a$FILE
tail
lee desde el ahora vacío$FILE
Si desea eliminar la primera línea dentro del archivo, debe usar:
Se
&&
asegurará de que el archivo no se sobrescriba cuando haya un problema.fuente
-r
opción. ¿Tal vez hay una configuración de búfer en algún lugar del sistema? ¿O-n
es un número con signo de 32 bits?tail
funcionará para cualquier tamaño de archivo.-n N means output the last N lines, instead of the last 10; or use +N to output lines starting with the Nth
Puede usar -i para actualizar el archivo sin usar el operador '>'. El siguiente comando eliminará la primera línea del archivo y la guardará en el archivo.
fuente
unterminated transform source string
sed -i '1,2d' filename
tail -n +2
. No estoy seguro de por qué no es la respuesta principal.Para aquellos que están en SunOS que no es GNU, el siguiente código ayudará:
fuente
No, eso es lo más eficiente que vas a conseguir. Podría escribir un programa 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 a medida que los archivos crecen (y supongo que son grandes si toma un minuto )
Pero su pregunta tiene el mismo problema que tantos otros, ya que supone la solución. Si nos dijera en detalle qué está tratando de hacer en lugar de cómo , podríamos sugerirle una mejor opción.
Por ejemplo, si este es un archivo A que procesa algún otro programa B, una solución sería no quitar la primera línea, sino modificar el programa B para procesarlo de manera diferente.
Digamos que todos sus programas se agregan a este archivo A y el programa B actualmente lee y procesa la primera línea antes de eliminarlo.
Puede rediseñar el programa B para que no intente eliminar la primera línea pero mantenga un desplazamiento persistente (probablemente basado en archivos) en el archivo A para que, la próxima vez que se ejecute, pueda buscar ese desplazamiento, procesar la línea allí y actualice el desplazamiento.
Luego, en un momento de silencio (¿medianoche?), Podría realizar un procesamiento especial del archivo A para eliminar todas las líneas procesadas actualmente y volver a establecer el desplazamiento en 0.
Sin duda será más rápido que un programa abra y busque un archivo en lugar de abrirlo y reescribirlo. Esta discusión supone que usted tiene control sobre el programa B, por supuesto. No sé si ese es el caso, pero puede haber otras posibles soluciones si proporciona más información.
fuente
awk FNR-1 *.csv
probablemente sea más rápido.Usted puede editar los archivos en su lugar: Sólo uso de Perl
-i
bandera, de esta manera:Esto hace que la primera línea desaparezca, como usted pregunta. Perl necesitará leer y copiar todo el archivo, pero organiza que la salida se guarde con el nombre del archivo original.
fuente
Puedes hacer esto fácilmente con:
en la línea de comando; o para eliminar la primera línea de un archivo de forma permanente, use el modo in situ de sed con la
-i
bandera:fuente
Como dijo Pax, probablemente no va a llegar más rápido que esto. La razón es que casi no hay sistemas de archivos que admitan el truncamiento desde el principio del archivo, por lo que esta será una
n
operación O ( ) donden
está 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?).fuente
La
sponge
utilidad evita la necesidad de hacer malabarismos con un archivo temporal:fuente
sponge
de hecho es mucho más limpio y robusto que la solución aceptada (tail -n +2 "$FILE" > "$FILE.tmp" && mv "$FILE.tmp" "$FILE"
)sponge
almacena el archivo completo en la memoria? Eso no funcionará si son cientos de GB.sponge
lo absorberá, ya que usa un archivo / tmp como un paso intermedio, que luego se usa para reemplazar el original después.Si desea modificar el archivo en su lugar, siempre se puede utilizar el original
ed
en lugar de su s sucesor treamingsed
:El
ed
comando era el editor de texto original de UNIX, incluso antes de que hubiera terminales de pantalla completa, y mucho menos estaciones de trabajo gráficas. Elex
editor, mejor conocido como lo que estás usando cuando se pulsa en el colon rápido envi
, es un ex versión de tendidoed
, por lo que muchos de los mismos comandos de trabajo. Si biened
está destinado a usarse de manera interactiva, también se puede usar en modo por lotes enviándole una cadena de comandos, que es lo que hace esta solución.La secuencia
<<<$'1d\nwq\n'
se aprovecha de apoyo del Golpe de aquí-cuerdas (<<<
) y citas POSIX ($'
...'
) a la entrada de alimentación aled
comando que consiste en dos líneas:1d
que d eletes línea 1 , y luegowq
, que w ritos la parte posterior archivo a disco y luego q sale de la sesión de edición.fuente
debería mostrar las líneas excepto la primera línea:
fuente
Podría usar vim para hacer esto:
Esto debería ser más rápido, ya que vim no leerá todo el archivo cuando se procese.
fuente
+wq!
si su shell es bash. Probablemente no, ya!
que no está al principio de una palabra, pero adquirir el hábito de citar cosas probablemente sea bueno en todos lados. (Y si busca una súper eficiencia al no citar innecesariamente, tampoco necesita las comillas1d
).¿Qué tal usar csplit?
fuente
csplit file /^.*$/1
. O más simplemente:csplit file //1
. O aún más simple:csplit file 2
.Como parece que no puedo acelerar la eliminación, creo que un buen enfoque podría ser procesar el archivo en lotes como este:
El inconveniente de esto es que si el programa 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)
fuente
Si lo que está buscando hacer es recuperarse después de una falla, puede crear un archivo que tenga lo que ha hecho hasta ahora.
fuente
Este liner hará:
Funciona, ya que
tail
se ejecuta antesecho
y luego el archivo se desbloquea, por lo tanto, no es necesario un archivo temporal.fuente
¿Usaría la cola en las líneas N-1 y la dirigiría a un archivo, luego eliminaría el archivo antiguo y cambiaría el nombre del nuevo archivo al antiguo nombre?
Si estuviera haciendo esto programáticamente, leería el archivo y recordaría el desplazamiento del archivo, después de leer cada línea, para poder volver a esa posición y leer el archivo con una línea menos.
fuente