Unix - голова и хвост файла - PullRequest
       19

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

116 голосов
/ 24 декабря 2011

Скажем, у вас есть текстовый файл, какая команда для одновременного просмотра первых 10 строк и 10 нижних строк файла?190-200 за один раз.

Ответы [ 19 ]

182 голосов
/ 24 декабря 2011

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

(head; tail) < file.txt

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

cat file.txt | (head; tail)

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

17 голосов
/ 24 декабря 2011

ed это standard text editor

$ echo -e '1+10,$-10d\n%p' | ed -s file.txt
11 голосов
/ 05 декабря 2013

Для чистого потока (например, вывод команды) вы можете использовать 'tee', чтобы разветвлять поток и отправлять один поток в заголовок и один в хвост. Для этого необходимо использовать функцию '> (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;'
5 голосов
/ 06 сентября 2017
(sed -u 10q; echo ...; tail) < file.txt

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

3 голосов
/ 24 декабря 2011

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

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

2 голосов
/ 30 июня 2017

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

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

Список возможностей:

  • прямой вывод для головы (очевидно, что для хвоста это невозможно)
  • не использовать внешние файлы
  • прогрессбар одна точка для каждой строки после MAX_LINES, очень полезно для длительных задач.
  • прогрессбар на stderr, гарантирующий, что точки прогресса отделены от головы + хвоста (очень удобно, если вы хотите передать стандартный вывод)
  • позволяет избежать возможного неправильного порядка ведения журнала из-за буферизации (stdbuf)
  • избегать дублирования вывода, когда общее количество строк меньше, чем head + tail.
2 голосов
/ 24 декабря 2011

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

инструменты, такие как 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
2 голосов
/ 21 сентября 2016

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

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
1 голос
/ 24 декабря 2011

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

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

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

1 голос
/ 04 апреля 2014

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...