Tengo un archivo con muchas filas, y cada fila tiene una marca de tiempo al comienzo, como
[Thread-3] (21/09/12 06:17:38:672) logged message from code.....
Por lo tanto, con frecuencia verifico 2 cosas de este archivo de registro.
- Las primeras filas, que tienen las condiciones globales y la hora de inicio también se dan.
- Últimas filas, que tiene el estado de salida con alguna otra información.
¿Hay algún comando único rápido y útil que me permita mostrar solo las primeras y últimas líneas de un archivo?
head and tail
funcionan?N
sed(1)
experto, pero hay formas de guardar cosas para usarlas más tarde. Quizás valga la pena mirar allí. OTOH, probablemente prepararía un script Perl (o lo que sea) para hacerlo si se usa con frecuencia, ya que estoy más familiarizado con eso.Respuestas:
Puedes usarlo
sed
oawk
hacerlo con un solo comando. Sin embargo perderás a la velocidad, causased
yawk
tendrá que ejecutar a través de todo el archivo de todos modos. Desde el punto de vista de la velocidad, es mucho mejor hacer una función o cada vez una combinación detail
+head
. Esto tiene el inconveniente de no funcionar si la entrada es una tubería, sin embargo, puede usar la sustitución de proceso, en caso de que su shell lo admita (vea el ejemplo a continuación).y simplemente lanzarlo como
para proceder con la sustitución del proceso (bash, zsh, ksh como shells solamente):
PD. incluso puede agregar un
grep
para verificar si existen sus "condiciones globales".fuente
-n 10
es el predeterminado, no?-n 10
No es necesario aquí.@rush tiene razón acerca de que usar head + tail es más eficiente para archivos grandes, pero para archivos pequeños (<20 líneas), algunas líneas pueden salir dos veces.
sería igualmente eficiente, pero no tendría el problema anterior.
fuente
{head; tail;} < file
funciona en zsh pero falla en sh.{ head; tail;} < file
siempre funciona Perdón por el ruido.head
, no con el shell. POSIX requierehead
dejar el cursor en el archivo justo después de esas 10 líneas para los archivos normales. Podría surgir un problema parahead
implementaciones que no son POSIX (versiones muy antiguas de GNU head solían ser no conformes en ese caso, pero estamos hablando de décadas) o si el archivo no es buscable (como el nombre de pipe o socket, pero luego el otra solución tendría el mismo problema).sudo sh -c '{ head; tail;} < /path/to/file'
La
{ head; tail; }
solución no funcionaría en tuberías (o sockets u otros archivos no buscables) porquehead
podría consumir demasiados datos a medida que se leen por bloques y no puede buscar en una tubería, dejando el cursor dentro del archivo más allá de lotail
que significa para seleccionar.Por lo tanto, podría usar una herramienta que lea un carácter a la vez como el del shell
read
(aquí usando una función que toma el número de líneas de cabecera y cola como argumentos).o implementar
tail
en awk por ejemplo como:Con
sed
:(aunque tenga en cuenta que algunas
sed
implementaciones tienen una limitación baja en el tamaño de su espacio de patrones, por lo que fallarían para valores grandes del número de líneas de cola).fuente
Usando la
bash
sustitución del proceso, puede hacer lo siguiente:Tenga en cuenta que no se garantiza que las líneas estén en orden, aunque para archivos de más de 8 KB, es muy probable que lo estén. Este límite de 8kB es el tamaño típico del búfer de lectura, y está relacionado con la razón por la
| {head; tail;}
que no funciona para archivos pequeños.El
cat >/dev/null
es necesario para mantenerhead
vivo el oleoducto. Detee
lo contrario, se cerrará antes, y aunque obtendrá la salidatail
, será desde algún lugar en el medio de la entrada, en lugar del final.Finalmente, ¿por qué, en
>/dev/null
lugar de, digamos, mudarsetail
a otro|
? En el siguiente caso:head
La salida estándar se alimenta a la tubería entail
lugar de a la consola, que no es lo que queremos en absoluto.fuente
tail
tiene que trabajar más tiempo, pero espero (y veo) que falle aproximadamente la mitad del tiempo para entradas cortas.tee >(head) >(tail)
por las mismas razones (>(...)
que por cierto es una función ksh que ahora es compatible con zsh y bash también) también usa tuberías. Podría hacerlo,... | (trap '' PIPE; tee >(head) >(tail) > /dev/null)
pero aún verá algunos mensajes de error de tuberías rotastee
.tail
es el que SIGPIPE está matando, notee
, ytail
no está escribiendo en una tubería. Entonces debe ser de unkill()
, ¿no ?. Y esto solo sucede cuando estoy usando la|
sintaxis.strace
dice quetee
no se llamakill()
... así que tal vezbash
?seq 100000 | tee >(head -n1) >(tail -n1) > /dev/null
Usando
ed
(que leerá todo el archivo en RAM):fuente
ed -s file <<< $'11,$-10d\n,p\nq\n'
La primera solución de Stephane en una función para que pueda usar argumentos (funciona en cualquier shell similar a Bourne o POSIX):
Ahora puedes hacer esto:
Por supuesto, esto supone que solo está viendo un archivo y, al igual que la solución de Stephane, funciona (confiablemente) solo en archivos normales (buscables).
fuente
Con la opción
-u
(--unbuffered
) de GNUsed
, puede usarlased -u 2q
como una alternativa sin búfer parahead -n2
:(head -n2;tail -n2)
falla cuando las últimas líneas son parte del bloque de la entrada que es consumida porhead
:fuente
Hoy me topé con algo así, donde solo necesitaba la última línea y algunas líneas desde el frente de una corriente y se me ocurrió lo siguiente.
Leí esto como: inicialice el espacio de espera con el contenido de la primera línea, agregue las líneas 2-3 en el espacio de espera, en EOF agregue la última línea al espacio de espera, intercambie el espacio de espera y patrón e imprima el patrón espacio.
Tal vez alguien con más
sed
-fu que yo pueda encontrar la manera de generalizar esta opción para imprimir las últimas pocas líneas de la corriente que se indican en esta pregunta, pero yo no lo necesitaba y no podía encontrar una manera fácil de hacer matemáticas en base a la$
dirección de ensed
o tal vez administrando el espacio de espera de modo que solo las últimas líneas estén en él cuandoEOF
se alcance.fuente
Puede probar Perl, si lo tiene instalado:
Esto funcionará para la mayoría de los archivos, pero lee todo el archivo en la memoria antes de procesarlo. Si no está familiarizado con las secciones de Perl, "0" entre corchetes significa "tomar la primera línea" y "-3 ...- 1" significa "tomar las últimas tres líneas". Puede adaptar ambos a sus necesidades. Si necesita procesar archivos realmente grandes (lo que es 'grande' puede depender de su RAM y quizás de los tamaños de intercambio), puede optar por:
puede ser algo más lento, porque hace un corte en cada iteración, pero es independiente del tamaño del archivo.
Ambos comandos deberían funcionar tanto en tuberías como con archivos normales.
fuente