Unix - head AND хвост файла

Скажем, у вас есть txt файл, какая команда для одновременного просмотра 10 верхних и нижних 10 строк файла?

то есть. если файл имеет длину 200 строк, то просматривайте строки 1-10 и 190-200 за один раз.

Ответ 1

Вы можете просто:

(head; tail) < file.txt

Примечание. Будут напечатаны дублированные строки, если количество строк в файле .txt меньше, чем строки по умолчанию в строке head + default.

Ответ 2

ed является standard text editor

$ echo -e '1+10,$-10d\n%p' | ed -s file.txt

Ответ 3

Для чистого потока (например, вывода из команды) вы можете использовать "tee" для форкирования потока и отправки одного потока в голову и от одного до хвоста. Для этого требуется использовать функцию " > (список)" bash (+/dev/fd/N):

( COMMAND | tee /dev/fd/3 | head ) 3> >( tail )

или используя /dev/fd/N (или/dev/stderr) плюс подоболочки со сложным перенаправлением:

( ( 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

(Ни один из них не будет работать в csh или tcsh.)

Для чего-то с немного лучшим контролем вы можете использовать эту команду perl:

COMMAND | perl -e 'my $size = 10; my @buf = (); while (<>) { print if $. <= $size; push(@buf, $_); if ( @buf > $size ) { shift(@buf); } } print "------\n"; print @buf;'

Ответ 4

проблема здесь в том, что поточно-ориентированные программы не знают длину файла заранее (потому что может быть не один, если это реальный поток).

инструменты, такие как tail, буферизуют последние n строк и ждут конца потока, затем печатают.

если вы хотите сделать это в одной команде (и работать с любым смещением и не повторять строки, если они перекрываются), вам придется подражать этому поведению, о котором я говорил.

попробуйте этот 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

Ответ 5

Первые 10 строк файла .ext, затем его последние 10 строк:

cat file.ext | head -10 && cat file.ext | tail -10

Последние 10 строк файла, затем первые 10:

cat file.ext | tail -10 && cat file.ext | head -10

Затем вы можете выполнить вывод в другом месте:

(cat file.ext | head -10 && cat file.ext | tail -10 ) | your_program

Ответ 6

head -10 file.txt; tail -10 file.txt

Кроме этого, вам нужно будет написать свою собственную программу/ script.

Ответ 7

Хорошо, вы всегда можете связать их вместе. Вот так, head fiename_foo && tail filename_foo. Если этого недостаточно, вы можете написать себе функцию bash в файле .profile или любом файле входа, который вы используете:

head_and_tail() {
    head $1 && tail $1
}

И позже вызовите его из командной строки: head_and_tail filename_foo.

Ответ 8

Почему бы не использовать sed для этой задачи?

sed -n -e 1,+9p -e 190,+9p textfile.txt

Ответ 9

Я написал простое приложение python для этого: https://gist.github.com/garyvdm/9970522

Он обрабатывает каналы (потоки), а также файлы.

Ответ 10

Чтобы обрабатывать каналы (потоки), а также файлы, добавьте их в файл .bashrc или .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] }' ; }

Тогда вы можете не только

headtail 10 < file.txt

но также

a.out | headtail 10

(Это все еще добавляет ложные пустые строки, когда 10 превышает входную длину, в отличие от обычного старого a.out | (head; tail). Спасибо, предыдущие респонденты.)

Примечание: headtail 10, а не headtail -10.

Ответ 11

опираясь на идеи выше (тестируемые bash и zsh)

но используя псевдоним "шляпа" Head and Tails

alias hat='(head -5 && echo "^^^------vvv" && tail -5) < '


hat large.sql

Ответ 12

На основе J.F. Комментарий Себастьяна:

cat file | { tee >(head >&3; cat >/dev/null) | tail; } 3>&1

Таким образом, вы можете обрабатывать первую строку, а остальные - по-разному в одном канале, что полезно для работы с данными 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

Ответ 13

Потребовалось много времени, чтобы закончить это решение, которое, кажется, единственное, что охватывало все варианты использования (пока):

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]}
           }'

Список функций:

  • живой выход для головы (очевидно, что для хвоста невозможно)
  • использование внешних файлов
  • progressbar по одной точке для каждой строки после MAX_LINES, очень полезная для длительных задач.
  • progressbar на stderr, уверяя, что точки прогресса отделены от головы + хвоста (очень удобно, если вы хотите вывести stdout)
  • позволяет избежать неправильного порядка ведения журнала из-за буферизации (stdbuf)
  • избегать дублирования вывода, когда общее количество строк меньше, чем голова + хвост.

Ответ 14

(sed -u 10q; echo ...; tail) < file.txt

Еще одна вариация темы (head;tail), но избегая проблемы с начальной загрузкой буфера для небольших файлов.

Ответ 15

Я искал это решение некоторое время. Пробовал сам с sed, но проблема с незнанием длины файла/потока была непреодолимой. Из всех доступных выше вариантов мне понравилось решение Camille Goudeseune awk. Он сделал заметку, что его решение оставило лишние пустые строки на выходе с достаточно небольшим набором данных. Здесь я предоставляю модификацию его решения, которое удаляет дополнительные строки.

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] }' ; }