varios una subdirectorios por mover ejemplos directorios crear consola como comandos carpeta basicos archivos archivo linux bash shell unix scripting

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 .



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.