Допустим, у вас есть текстовый файл. Какая команда позволяет просматривать 10 верхних и 10 нижних строк файла одновременно?
т.е. если файл состоит из 200 строк, то просматривайте строки 1-10 и 190-200 за один раз.
Допустим, у вас есть текстовый файл. Какая команда позволяет просматривать 10 верхних и 10 нижних строк файла одновременно?
т.е. если файл состоит из 200 строк, то просматривайте строки 1-10 и 190-200 за один раз.
Ответы:
Вы можете просто:
(head; tail) < file.txt
А если вам по какой-то причине нужно использовать трубы, то вот так:
cat file.txt | (head; tail)
Примечание: будет печатать повторяющиеся строки, если количество строк в файле file.txt меньше, чем строки заголовка по умолчанию + строки хвоста по умолчанию.
head
как потребляет первые 10 строк файла. (Сравните это с head < file.txt; tail < file.txt
файлом, в котором меньше 20 строк). Это очень незначительный момент, о котором нужно помнить. (Но все же +1.)
head
только первые 10 строк своего ввода, нет гарантии, что он не потреблял его больше, чтобы найти окончание 10-й строки, оставляя для отображения меньшую часть ввода . less
seq 100 | (head; tail)
дает мне только первые 10 чисел. Только при гораздо большем размере ввода (например seq 2000
) хвост получает некоторый ввод.
Для чистого потока (например, вывода из команды) вы можете использовать «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;'
COMMAND | { tee >(head >&2) | tail; } |& other_commands
cat >/dev/null
исправляет:COMMAND | { tee >(head >&2; cat >/dev/null) | tail; } |& other_commands
head
и tail
командами: \ ...
head -10 file.txt; tail -10 file.txt
Помимо этого, вам нужно будет написать свою собственную программу / сценарий.
cat
и / head
или tail
трубку, приятно знать, что я могу использовать их индивидуально!
{ head file; tail file; } | prog
(требуется
На основании комментария Дж. Ф. Себастьяна :
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
Н * 2 2 4 6
проблема здесь в том, что потоковые программы не знают заранее длину файла (потому что его может и не быть, если это настоящий поток).
такие инструменты, как 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
a.out | awk -v ...
Потребовалось много времени, чтобы получить это решение, которое, кажется, единственное, которое охватывает все варианты использования (пока):
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]}
}'
Список возможностей:
Я давно искал это решение. Сам пробовал с sed, но проблема с незнанием длины файла / потока заранее была непреодолимой. Из всех доступных выше вариантов мне нравится awk-решение Camille Goudeseune. Он сделал заметку, что его решение оставило лишние пустые строки в выводе с достаточно небольшим набором данных. Здесь я предлагаю модификацию его решения, убирающую лишние строки.
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] }' ; }
Что ж, вы всегда можете связать их вместе. Вроде так
head fiename_foo && tail filename_foo
,. Если этого недостаточно, вы можете написать себе функцию bash в своем файле .profile или любом файле входа, который вы используете:
head_and_tail() {
head $1 && tail $1
}
И, потом вызвать его из оболочки командной строки: head_and_tail filename_foo
.
Первые 10 строк файла file.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
tail
и head
или функции по псевдониму-джеями его.
Для этого я написал простое приложение на Python: https://gist.github.com/garyvdm/9970522
Он обрабатывает каналы (потоки), а также файлы.
Чтобы обрабатывать каналы (потоки), а также файлы, добавьте это в свой файл .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
.
Основываясь на том, что @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; $(( $(wc -l ${aFile} | grep -oE "^[[:digit:]]+")-9 )),\$p" "${aFile}"
ПРИМЕЧАНИЕ . Переменная aFile содержит полный путь к файлу .
Я бы сказал, что в зависимости от размера файла активное чтение его содержимого может быть нежелательным. В этом случае, я думаю, будет достаточно простого сценария оболочки.
Вот как я недавно обработал это для ряда очень больших файлов CSV, которые я анализировал:
$ for file in *.csv; do echo "### ${file}" && head ${file} && echo ... && tail ${file} && echo; done
Это распечатает первые 10 строк и последние 10 строк каждого файла, а также распечатает имя файла и несколько многоточий до и после.
Для одного большого файла вы можете просто запустить следующее для того же эффекта:
$ head somefile.csv && echo ... && tail somefile.csv
Потребляет стандартный ввод, но прост и работает в 99% случаев использования
#!/usr/bin/env bash
COUNT=${1:-10}
IT=$(cat /dev/stdin)
echo "$IT" | head -n$COUNT
echo "..."
echo "$IT" | tail -n$COUNT
$ seq 100 | head_and_tail 4
1
2
3
4
...
97
98
99
100