Скажімо, у вас є файл txt, яка команда для перегляду верхнього 10 рядка та нижнього 10 рядків файлу одночасно?
тобто, якщо файл довжиною 200 рядків, то переглядайте рядки 1-10 та 190-200 за один раз.
Скажімо, у вас є файл txt, яка команда для перегляду верхнього 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', щоб розщедрити потік і надіслати один потік в голову і один в хвіст. Для цього потрібно використовувати або '> (список)' функцію 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
N * 2 2 4 6
Проблема тут полягає в тому, що програми, орієнтовані на потік, не знають заздалегідь довжину файлу (тому що може бути не один, якщо це справжній потік).
такі інструменти, як tail
буфер останніх п ятих рядків, які бачили, і чекають кінця потоку, після чого друкують.
якщо ви хочете зробити це в одній команді (і вона буде працювати з будь-яким зміщенням, і не повторюйте рядки, якщо вони перетинаються), вам доведеться наслідувати цю поведінку, яку я згадав.
спробуйте цей див:
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, але проблема з тим, що заздалегідь не знати довжини файлу / потоку, була непереборною. З усіх варіантів, доступних вище, мені подобається ексклюзивне рішення Каміля Годесюна. Він зробив зауваження, що його рішення залишило зайві порожні рядки у висновку з досить невеликим набором даних. Тут я надаю модифікацію його рішення, яка видаляє зайві лінії.
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
Споживає stdin, але простий і працює на 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