unix-голова и хвост файла



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



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

571   18  

18 ответов:

можно просто:

(head; tail) < file.txt

и если вам нужно использовать трубы по какой-то причине, то вот так:

cat file.txt | (head; tail)

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

ed это standard text editor

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

для чистого потока (например, выход из команды), вы можете использовать "тройник", чтобы разветвить поток и отправить один поток в голову и один в хвост. Для этого необходимо использовать либо функцию '> (list) ' 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;'

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

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

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

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

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

попробуйте это awk:

awk -v offset=10 '{ if (NR <= offset) print; else { a[NR] = ; delete a[NR-offset] } } END { for (i=NR-offset+1; i<=NR; i++) print a[i] }' yourfile

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

head_and_tail() {
    head  && tail 
}

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

первые 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

Я написал простое приложение python, чтобы сделать это: https://gist.github.com/garyvdm/9970522

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

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

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

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

но используя псевдоним 'шляпа' голова и хвосты

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


hat large.sql

на основе комментарий Дж. Ф. Себастьяна:

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 *2}'; } 3>&1
N*2
2
4
6

чтобы обрабатывать трубы (потоки), а также файлы, добавьте это в свой .bashrc или .файл профиля:

headtail() { awk -v offset="" '{ if (NR <= offset) print; else { a[NR] = ; 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.

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

command | tee full.log | stdbuf -i0 -o0 -e0 awk -v offset=${MAX_LINES:-200} \
          '{
               if (NR <= offset) print;
               else {
                   a[NR] = ;
                   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)
  • избегайте дублирования вывода, когда общее количество строк меньше, чем head + tail.
(sed -u 10q; echo ...; tail) < file.txt

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

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

headtail() { awk -v offset="" '{ if (NR <= offset) print; else { a[NR] = ; 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] }' ; }

основываясь на том, что @Samus_ объяснил здесь о том, как работает команда @Aleksandra Zalcman, этот вариант удобен, когда вы не можете быстро определить, где начинается хвост без подсчета строк.

{ head; echo "####################\n...\n####################"; tail; } < file.txt

или если вы начинаете работать с чем-то другим, чем 20 строк, количество строк может даже помочь.

{ head -n 18; tail -n 14; } < file.txt | cat -n

чтобы напечатать первые 10 и последние 10 строк файла, вы могли бы попробовать это:

cat <(head -n10 file.txt) <(tail -n10 file.txt) | less

вы можете:

sed -n '1,10p; 190,$p' aFile

Comments

    Ничего не найдено.