
Probé suerte con grep
y sed
pero de alguna manera no logro hacerlo bien.
Tengo un archivo de registro que tiene un tamaño de aproximadamente 8 GB. Necesito analizar un período de 15 minutos de actividad sospechosa. Localicé la parte del archivo de registro que necesito ver y estoy intentando extraer esas líneas y guardarlas en un archivo separado. ¿Cómo haría eso en una máquina CentOS normal?
Mi último intento fue este pero no funcionó. Estoy perdido cuando se trata de sed
ese tipo de comandos.
sed -n '2762818,2853648w /var/log/output.txt' /var/log/logfile
Respuesta1
sed -n '2762818,2853648p' /var/log/logfile > /var/log/output.txt
p
es para imprimir
Respuesta2
Probablemente la mejor manera de hacerlo es con la redirección de shell, como otros han mencionado. sed
sin embargo, si bien es un favorito personal, probablemente no lo hará de manera más eficiente que lo hará head
, que está diseñado para capturar solo una cantidad determinada de líneas de un archivo.
Hay otras respuestas en este sitio que demuestran de manera demostrable que los archivos grandes head -n[num] | tail -n[num]
tendrán un rendimiento superior sed
en todo momento, pero probablemente incluso más rápido que eso es evitar la tubería por completo.
Creé un archivo como:
echo | dd cbs=5000000 conv=block | tr \ \\n >/tmp/5mil_lines
Y lo repasé:
{ head -n "$((ignore=2762817))" >&2
head -n "$((2853648-ignore))"
} </tmp/5mil_lines 2>/dev/null |
sed -n '1p;$p'
Solo usé sed
allí para tomar solo la primera y la última línea para mostrarles...
2762818
2853648
Esto funciona porque cuando agrupa comandos { ... ; }
y redirige la entrada para el grupo, ... ; } <input
todos compartirán la misma entrada. La mayoría de los comandos agotarán todo el archivo mientras lo leen, por lo que en un { cmd1 ; cmd2; } <infile
caso generalmente cmd1
se lee desde el principio del archivo hasta el final y cmd2
no queda nada.
head
, sin embargo, siempre buscará sólo hasta donde se le indique en su archivo, y así en un...
{ head -n [num] >/dev/null
head -n [num]
} <infile
... caso el primero busca [num]
y vuelca su salida /dev/null
y el segundo se deja para comenzar su lectura donde lo dejó el primero.
Tu puedes hacer...
{ head -n "$((ignore=2762817))" >/dev/null
head -n "$((2853648-ignore))" >/path/to/outfile
} <infile
Esta construcción también funciona con otros tipos de comandos compuestos. Por ejemplo:
set "$((n=2762817))" "$((2853648-n))"
for n do head "-n$n" >&"$#"; shift
done <5mil_lines 2>/dev/null |
sed -n '1p;$p'
...que imprime...
2762818
2853648
Pero también podría funcionar así:
d=$((( n=$(wc -l </tmp/5mil_lines))/43 )) &&
until [ "$(((n-=d)>=(!(s=143-n/d))))" -eq 0 ] &&
head "-n$d" >>"/tmp/${s#1}.split"
do head "-n$d" > "/tmp/${s#1}.split" || ! break
done </tmp/5mil_lines
Arriba del shell inicialmente establece las variables $n
y $d
en ...
$n
- El recuento de líneas según lo informado por
wc
mi archivo de prueba./tmp/5mil_lines
- El recuento de líneas según lo informado por
$d
- El cociente de
$n/43
donde 43 es simplemente algún divisor seleccionado arbitrariamente.
- El cociente de
Luego repite until
lo que ha disminuido $n
a $d
un valor less $d
. Mientras lo hace, guarda su recuento dividido $s
y usa ese valor en el bucle para incrementar el >
archivo de salida nombrado llamado /tmp/[num].split
. El resultado es que lee un número igual de \n
campos delimitados por ewline en su archivo de entrada en un nuevo archivo de salida para cada iteración, dividiéndolo igualmente 43 veces a lo largo del ciclo. Lo administra sin tener que leer su archivo interno más de 2 veces: la primera vez es cuando wc
cuenta sus líneas y durante el resto de la operación solo lee tantas líneas como escribe en el archivo externo cada vez.
Después de ejecutarlo verifiqué mis resultados como...
tail -n1 /tmp/*split | grep .
PRODUCCIÓN:
==> /tmp/01.split <==
116279
==> /tmp/02.split <==
232558
==> /tmp/03.split <==
348837
==> /tmp/04.split <==
465116
==> /tmp/05.split <==
581395
==> /tmp/06.split <==
697674
==> /tmp/07.split <==
813953
==> /tmp/08.split <==
930232
==> /tmp/09.split <==
1046511
==> /tmp/10.split <==
1162790
==> /tmp/11.split <==
1279069
==> /tmp/12.split <==
1395348
==> /tmp/13.split <==
1511627
==> /tmp/14.split <==
1627906
==> /tmp/15.split <==
1744185
==> /tmp/16.split <==
1860464
==> /tmp/17.split <==
1976743
==> /tmp/18.split <==
2093022
==> /tmp/19.split <==
2209301
==> /tmp/20.split <==
2325580
==> /tmp/21.split <==
2441859
==> /tmp/22.split <==
2558138
==> /tmp/23.split <==
2674417
==> /tmp/24.split <==
2790696
==> /tmp/25.split <==
2906975
==> /tmp/26.split <==
3023254
==> /tmp/27.split <==
3139533
==> /tmp/28.split <==
3255812
==> /tmp/29.split <==
3372091
==> /tmp/30.split <==
3488370
==> /tmp/31.split <==
3604649
==> /tmp/32.split <==
3720928
==> /tmp/33.split <==
3837207
==> /tmp/34.split <==
3953486
==> /tmp/35.split <==
4069765
==> /tmp/36.split <==
4186044
==> /tmp/37.split <==
4302323
==> /tmp/38.split <==
4418602
==> /tmp/39.split <==
4534881
==> /tmp/40.split <==
4651160
==> /tmp/41.split <==
4767439
==> /tmp/42.split <==
4883718
==> /tmp/43.split <==
5000000
Respuesta3
Probablemente puedas lograr esto con la ayuda de head
las tail
combinaciones de comandos que se muestran a continuación.
head -n{to_line_number} logfile | tail -n+{from_line_number} > newfile
Reemplace from_line_number
y to_line_number
con los números de línea que desee.
Pruebas
cat logfile
This is first line.
second
Third
fourth
fifth
sixth
seventh
eighth
ninth
tenth
##I use the command as below. I extract from 4th line to 10th line.
head -n10 logfile | tail -n+4 > newfile
fourth
fifth
sixth
seventh
eighth
ninth
tenth