linux - una - unix-cabeza Y cola del archivo
crear directorios y subdirectorios en linux (17)
Supongamos que tiene un archivo txt, ¿cuál es el comando para ver las 10 líneas principales y las 10 líneas inferiores de archivos simultáneamente?
es decir, si el archivo tiene 200 líneas de longitud, entonces vea las líneas 1-10 y 190-200 de una vez.
¿Por qué no usar sed
para esta tarea?
sed -n -e 1,+9p -e 190,+9p textfile.txt
Basado en el comentario de JF Sebastian :
cat file | { tee >(head >&3; cat >/dev/null) | tail; } 3>&1
De esta forma, puede procesar la primera línea y el resto de manera diferente en un solo conducto, lo cual 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 6
Bueno, siempre puedes encadenarlos juntos. Como tal, head fiename_foo && tail filename_foo
. Si eso no es suficiente, puede escribir usted mismo una función bash en su archivo .profile o cualquier archivo de inicio de sesión que utilice:
head_and_tail() {
head $1 && tail $1
}
Y, más tarde, invocarlo desde el intérprete de comandos de su shell: head_and_tail filename_foo
.
Escribí una aplicación de Python simple para hacer esto: https://gist.github.com/garyvdm/9970522
Maneja tuberías (flujos) así como también archivos.
He estado buscando esta solución por un tiempo. Lo intenté con sed, pero el problema de no saber la longitud del archivo / stream de antemano era insuperable. De todas las opciones disponibles anteriormente, me gusta la solución awk de Camille Goudeseune. Hizo una nota que su solución dejó 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] }'' ; }
Para manejar pipes (streams) y archivos, agrégalo a tu 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 falsas cuando 10 excede la longitud de la entrada, a diferencia del antiguo a.out | (head; tail)
. Gracias, respuestas anteriores).
Nota: headtail 10
, no headtail -10
.
Para un flujo puro (por ejemplo, salida de un comando), puede usar ''tee'' para bifurcar el flujo y enviar un flujo a la cabeza y uno 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 una redirección complicada:
( ( 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 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;''
Primeras 10 líneas de archivo.ext, luego sus últimas 10 líneas:
cat file.ext | head -10 && cat file.ext | tail -10
Las últimas 10 líneas del archivo, luego las primeras 10:
cat file.ext | tail -10 && cat file.ext | head -10
A continuación, puede canalizar la salida a otra parte también:
(cat file.ext | head -10 && cat file.ext | tail -10 ) | your_program
Puedes simplemente:
(head; tail) < file.txt
Nota: imprimirá líneas duplicadas si el número de líneas en file.txt es más pequeño que las líneas de cabeza predeterminadas + líneas de cola predeterminadas.
Sobre la base de lo que @Samus_ explicó here 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 las líneas.
{ head; echo "####################/n.../n####################"; tail; } < file.txt
O si comienzas a trabajar con algo más que 20 líneas, un conteo de líneas podría incluso ayudar.
{ head -n 18; tail -n 14; } < file.txt | cat -n
Tú también puedes:
sed -n ''1,10p; 190,$p'' aFile
Tomó mucho tiempo terminar con esta solución, que parece ser la única que cubría 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:
- salida en vivo para la cabeza (obviamente eso para la cola no es posible)
- no uso de archivos externos
- progressbar un punto para cada línea después de MAX_LINES, muy útil para tareas de larga ejecución.
- progressbar en stderr, asegurándose de que los puntos de progreso estén separados del head + tail (muy útil si quiere pipe stdout)
- evita una posible orden incorrecta de registro debido al almacenamiento en búfer (stdbuf)
- evite duplicar la salida cuando el número total de líneas es más pequeño que la cabeza + cola.
aprovechando las ideas anteriores (probado bash y zsh)
pero usando un alias ''hat'' Head and Tails
alias hat=''(head -5 && echo "^^^------vvv" && tail -5) < ''
hat large.sql
el problema aquí es que los programas orientados a flujo no conocen la longitud del archivo por adelantado (porque puede que no haya uno, si es un flujo real).
herramientas como la memoria intermedia de tail
las últimas n líneas vistas y espere hasta el final de la secuencia, luego imprima.
si desea hacer esto en un solo comando (y hacer que funcione con cualquier desplazamiento, y no repetir 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
ed
es el standard text editor
$ echo -e ''1+10,$-10d/n%p'' | ed -s file.txt
head -10 file.txt; tail -10 file.txt
Aparte de eso, necesitarás escribir tu propio programa / script.
(sed -u 10q; echo ...; tail) < file.txt
Simplemente otra variación en el tema (head;tail)
, pero evitando el problema de llenado del búfer inicial para archivos pequeños.