Допустим, у вас есть текстовый файл. Какая команда позволяет просматривать 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