Digamos que tiene un archivo txt, ¿cuál es el comando para ver las 10 líneas superiores y las 10 líneas inferiores del archivo simultáneamente?
es decir, si el archivo tiene 200 líneas de largo, visualice las líneas 1-10 y 190-200 de una vez.
Digamos que tiene un archivo txt, ¿cuál es el comando para ver las 10 líneas superiores y las 10 líneas inferiores del archivo simultáneamente?
es decir, si el archivo tiene 200 líneas de largo, visualice las líneas 1-10 y 190-200 de una vez.
Respuestas:
Puedes simplemente:
(head; tail) < file.txt
Y si necesita usar tuberías por alguna razón, entonces así:
cat file.txt | (head; tail)
Nota: imprimirá líneas duplicadas si el número de líneas en file.txt es menor que las líneas predeterminadas de encabezado + líneas predeterminadas de cola.
head
haber consumido las primeras 10 líneas del archivo. (Compare esto con head < file.txt; tail < file.txt
un archivo con menos de 20 líneas). Solo un punto muy pequeño a tener en cuenta. (Pero aún así +1.)
head
solo muestra las primeras 10 líneas de su entrada, no se garantiza que no haya consumido más para encontrar el final de la décima línea, dejando menos de la entrada para less
mostrar.
seq 100 | (head; tail)
me da solo los primeros 10 números. Solo en un tamaño de entrada mucho más grande (como seq 2000
) la cola recibe algo de entrada.
Para una secuencia pura (por ejemplo, salida de un comando), puede usar 'tee' para bifurcar la secuencia y enviar una secuencia a la cabeza y otra a la cola. Esto requiere el uso de la función '> (lista)' de bash (+ / dev / fd / N):
( COMMAND | tee /dev/fd/3 | head ) 3> >( tail )
o usando / dev / fd / N (o / dev / stderr) más subcapas con redireccionamiento complicado:
( ( seq 1 100 | tee /dev/fd/2 | head 1>&3 ) 2>&1 | tail ) 3>&1
( ( seq 1 100 | tee /dev/stderr | head 1>&3 ) 2>&1 | tail ) 3>&1
(Ninguno de estos funcionará en csh o tcsh).
Para algo con un poco de mejor control, puede usar este comando perl:
COMMAND | perl -e 'my $size = 10; my @buf = (); while (<>) { print if $. <= $size; push(@buf, $_); if ( @buf > $size ) { shift(@buf); } } print "------\n"; print @buf;'
COMMAND | { tee >(head >&2) | tail; } |& other_commands
cat >/dev/null
lo corrige:COMMAND | { tee >(head >&2; cat >/dev/null) | tail; } |& other_commands
head
y tail
comandos: \ ...
head -10 file.txt; tail -10 file.txt
Aparte de eso, necesitarás escribir tu propio programa / script.
cat
y / head
o tail
entubado, ¡es bueno saber que puedo usarlos individualmente!
{ head file; tail file; } | prog
(espaciado dentro de las llaves, y el punto y coma final son obligatorios)
Basado en el comentario de JF Sebastian :
cat file | { tee >(head >&3; cat >/dev/null) | tail; } 3>&1
De esta manera, puede procesar la primera línea y el resto de manera diferente en una sola tubería, lo que es útil para trabajar con datos CSV:
{ echo N; seq 3;} | { tee >(head -n1 | sed 's/$/*2/' >&3; cat >/dev/null) | tail -n+2 | awk '{print $1*2}'; } 3>&1
N * 2 2 4 4 6 6
El problema aquí es que los programas orientados a secuencias no conocen de antemano la longitud del archivo (porque puede que no haya uno, si es una secuencia real).
herramientas como tail
almacenar las últimas n líneas vistas y esperar el final de la transmisión, luego imprimir.
si desea hacer esto en un solo comando (y hacer que funcione con cualquier desplazamiento, y no repita líneas si se superponen) tendrá que emular este comportamiento que mencioné.
prueba este awk:
awk -v offset=10 '{ if (NR <= offset) print; else { a[NR] = $0; delete a[NR-offset] } } END { for (i=NR-offset+1; i<=NR; i++) print a[i] }' yourfile
a.out | awk -v ...
Me llevó mucho tiempo terminar con esta solución, que parece ser la única que cubrió todos los casos de uso (hasta ahora):
command | tee full.log | stdbuf -i0 -o0 -e0 awk -v offset=${MAX_LINES:-200} \
'{
if (NR <= offset) print;
else {
a[NR] = $0;
delete a[NR-offset];
printf "." > "/dev/stderr"
}
}
END {
print "" > "/dev/stderr";
for(i=NR-offset+1 > offset ? NR-offset+1: offset+1 ;i<=NR;i++)
{ print a[i]}
}'
Lista de características:
He estado buscando esta solución por un tiempo. Lo intenté yo mismo con sed, pero el problema de no saber de antemano la longitud del archivo / flujo era insuperable. De todas las opciones disponibles anteriormente, me gusta la solución awk de Camille Goudeseune. Él hizo una nota de que su solución dejaba líneas en blanco adicionales en la salida con un conjunto de datos suficientemente pequeño. Aquí proporciono una modificación de su solución que elimina las líneas adicionales.
headtail() { awk -v offset="$1" '{ if (NR <= offset) print; else { a[NR] = $0; delete a[NR-offset] } } END { a_count=0; for (i in a) {a_count++}; for (i=NR-a_count+1; i<=NR; i++) print a[i] }' ; }
Bueno, siempre puedes encadenarlos juntos. Me gusta así
head fiename_foo && tail filename_foo
. Si eso no es suficiente, puede escribir una función bash en su archivo .profile o en cualquier archivo de inicio de sesión que utilice:
head_and_tail() {
head $1 && tail $1
}
Y, más tarde invocarla desde el shell de comandos: head_and_tail filename_foo
.
Primeras 10 líneas de archivo.ext, luego sus últimas 10 líneas:
cat file.ext | head -10 && cat file.ext | tail -10
Últimas 10 líneas del archivo, luego las primeras 10:
cat file.ext | tail -10 && cat file.ext | head -10
Luego puede canalizar la salida en otro lugar también:
(cat file.ext | head -10 && cat file.ext | tail -10 ) | your_program
tail
y head
o una función por alias-Ing ella.
Escribí una aplicación simple de Python para hacer esto: https://gist.github.com/garyvdm/9970522
Maneja tuberías (flujos) y archivos.
Para manejar tuberías (streams) así como archivos, agregue esto a su archivo .bashrc o .profile:
headtail() { awk -v offset="$1" '{ if (NR <= offset) print; else { a[NR] = $0; delete a[NR-offset] } } END { for (i=NR-offset+1; i<=NR; i++) print a[i] }' ; }
Entonces no solo puedes
headtail 10 < file.txt
pero también
a.out | headtail 10
(Esto todavía agrega líneas en blanco espurias cuando 10 excede la longitud de la entrada, a diferencia de la anterior a.out | (head; tail)
. Gracias, respondedores anteriores).
Nota: headtail 10
no headtail -10
.
Sobre la base de lo que @Samus_ explicó aquí sobre cómo funciona el comando de @Aleksandra Zalcman, esta variación es útil cuando no se puede detectar rápidamente dónde comienza la cola sin contar líneas.
{ head; echo "####################\n...\n####################"; tail; } < file.txt
O si comienza a trabajar con algo más que 20 líneas, un recuento de líneas podría incluso ayudar.
{ head -n 18; tail -n 14; } < file.txt | cat -n
Para imprimir las primeras 10 y últimas 10 líneas de un archivo, puede intentar esto:
cat <(head -n10 file.txt) <(tail -n10 file.txt) | less
sed -n "1,10p; $(( $(wc -l ${aFile} | grep -oE "^[[:digit:]]+")-9 )),\$p" "${aFile}"
NOTA : La variable aFile contiene la ruta completa del archivo .
Yo diría que dependiendo del tamaño del archivo, leer activamente en su contenido puede no ser deseable. En esa circunstancia, creo que deberían bastar algunas secuencias de comandos de shell simples.
Así es como recientemente manejé esto para varios archivos CSV muy grandes que estaba analizando:
$ for file in *.csv; do echo "### ${file}" && head ${file} && echo ... && tail ${file} && echo; done
Esto imprime las primeras 10 líneas y las últimas 10 líneas de cada archivo, al tiempo que imprime el nombre de archivo y algunos puntos suspensivos antes y después.
Para un solo archivo grande, simplemente puede ejecutar lo siguiente para obtener el mismo efecto:
$ head somefile.csv && echo ... && tail somefile.csv
Consume stdin, pero simple y funciona para el 99% de los casos de uso
#!/usr/bin/env bash
COUNT=${1:-10}
IT=$(cat /dev/stdin)
echo "$IT" | head -n$COUNT
echo "..."
echo "$IT" | tail -n$COUNT
$ seq 100 | head_and_tail 4
1
2
3
4
...
97
98
99
100