Ściśle mówiąc, nie daje to ogona oryginalnego pliku, ale koniec strumienia po headzużyciu pierwszych 10 wierszy pliku. (Porównaj to z head < file.txt; tail < file.txtplikiem zawierającym mniej niż 20 linii). Tylko bardzo drobna kwestia, o której należy pamiętać. (Ale wciąż +1.)
chepner
15
Ładny. Jeśli chcesz mieć przerwę między częściami głowy i ogona: (głowa; echo; ogon) <file.txt
Simon Hibbs
3
Ciekawe, dlaczego / jak to działa.
Zadano
9
@nametal Właściwie możesz nawet nie dostać tego dużo. Chociaż wyświetlahead tylko pierwsze 10 wierszy swojego wejścia, nie ma gwarancji, że nie zużywa go więcej w celu znalezienia końca dziesiątego wiersza, pozostawiając mniej wejścia do wyświetlenia. less
chepner
20
Przykro mi to mówić, ale odpowiedź działa tylko w niektórych przypadkach. seq 100 | (head; tail)daje mi tylko pierwsze 10 liczb. Tylko przy znacznie większym rozmiarze wejściowym (takim jak seq 2000) ogon otrzymuje pewne dane wejściowe.
Co się stanie, jeśli plik ma więcej lub mniej niż 200 wierszy? Nie znasz liczby linii ab initio?
Paul
@Paul Zmieniłem się sednaed
kev
15
W przypadku czystego strumienia (np. Wyjście z polecenia), możesz użyć „tee”, aby rozwidlić strumień i wysłać jeden strumień do głowy i jeden do końca. Wymaga to użycia funkcji '> (list)' w bash (+ / dev / fd / N):
( COMMAND | tee /dev/fd/3 | head ) 3> >( tail )
lub używając / dev / fd / N (lub / dev / stderr) plus podpowłoki ze skomplikowanym przekierowaniem:
( ( 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
(Żadne z nich nie będzie działać w csh ani tcsh).
Aby uzyskać trochę lepszą kontrolę, możesz użyć tego polecenia perla:
COMMAND | perl -e 'my $size = 10; my @buf = (); while (<>) { print if $. <= $size; push(@buf, $_); if ( @buf > $size ) { shift(@buf); } } print "------\n"; print @buf;'
+1 za obsługę strumienia. Możesz ponownie użyć stderr:COMMAND | { tee >(head >&2) | tail; } |& other_commands
jfs
2
btw, psuje się dla plików większych niż rozmiar bufora (8K w moim systemie). cat >/dev/nullnaprawia to:COMMAND | { tee >(head >&2; cat >/dev/null) | tail; } |& other_commands
jfs
Spodobało mi się to rozwiązanie, ale po kilku chwilach grania zauważyłem, że w niektórych przypadkach ogon biegał przed głową ... nie ma gwarantowanej kolejności między komendami headi tail: \ ...
Jan
8
(sed -u 10q; echo ...; tail) < file.txt
Kolejna odmiana (head;tail)motywu, ale unikająca początkowego problemu z wypełnianiem bufora w przypadku małych plików.
Fajnie, zawsze używałem cati / headlub tailrurami, dobrze wiedzieć, że mogę ich używać indywidualnie!
Paul
Jak mogę następnie przesłać te pierwsze 10 + ostatnie 10 do innego polecenia?
toop
1
@Paul - z 'your_program' jako wc -l zwraca 10 zamiast 20
toop
3
lub bez konieczności odradzania podpowłoki: { head file; tail file; } | prog(wymagane są odstępy wewnątrz nawiasów klamrowych i końcowy średnik)
glenn jackman
1
Wow ... głos negatywny za otrzymanie odpowiedzi dość podobnej do innych (ale z sygnaturą czasową przed nimi) po prawie dwóch latach, od kogoś, kto zdecydował się nie publikować, dlaczego głosował w dół. Ładny!
Problem polega na tym, że programy zorientowane strumieniowo nie znają z wyprzedzeniem długości pliku (ponieważ może go nie być, jeśli jest to prawdziwy strumień).
narzędzia takie jak tailbuforowanie ostatnich n widzianych wierszy i czekanie na koniec strumienia, a następnie drukowanie.
jeśli chcesz to zrobić za pomocą jednego polecenia (i chcesz, aby działało z dowolnym przesunięciem i nie powtarzaj wierszy, jeśli się nakładają), będziesz musiał emulować to zachowanie, o którym wspomniałem.
spróbuj tego 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
Od jakiegoś czasu szukałem tego rozwiązania. Wypróbowałem to sam z sedem, ale problem braku znajomości długości pliku / strumienia był nie do pokonania. Ze wszystkich opcji dostępnych powyżej podoba mi się rozwiązanie awk Camille Goudeseune. Zanotował, że jego rozwiązanie pozostawiło dodatkowe puste wiersze na wyjściu z wystarczająco małym zestawem danych. Tutaj podaję modyfikację jego rozwiązania, która usuwa dodatkowe linie.
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] }' ; }
Cóż, zawsze możesz je połączyć. Tak jak tak
head fiename_foo && tail filename_foo. Jeśli to nie wystarczy, możesz napisać sobie funkcję bash w swoim pliku .profile lub dowolnym pliku logowania, którego używasz:
head_and_tail() {
head $1 && tail $1
}
A później powołać go z powłoki wiersza: head_and_tail filename_foo.
Po co używać cat, skoro możesz po prostu zadzwonić do pliku head -10 file.txt?
jstarek
Czy możesz zmienić liczbę wierszy, aby wywołanie wyglądało mniej więcej tak: head_ tail (foo, m, n) - zwracanie pierwszego m snd ostatniego n wierszy tekstu?
Ricardo
@ricardo, co wymagałoby napisania skryptu bash, który pobiera 3 argumenty i przekazuje je do funkcji taili / headlub, tworząc jej alias.
Działa to dla plików o znanej długości, ale nie dla plików o nieznanej długości.
Kevin
0
Aby obsłużyć potoki (strumienie), a także pliki, dodaj to do pliku .bashrc lub .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] }' ; }
Wtedy możesz nie tylko
headtail 10 < file.txt
ale również
a.out | headtail 10
(To nadal dodaje fałszywe puste wiersze, gdy 10 przekracza długość wejścia, w przeciwieństwie do zwykłego starego a.out | (head; tail). Dziękuję, poprzednie osoby odpowiadające).
Opierając się na tym, co @Samus_ wyjaśnił tutaj o tym, jak działa polecenie @Aleksandra Zalcman, ta odmiana jest przydatna, gdy nie można szybko zlokalizować początku ogona bez liczenia linii.
Powiedziałbym, że w zależności od rozmiaru pliku, aktywne czytanie jego zawartości może nie być pożądane. W takiej sytuacji myślę, że wystarczy prosty skrypt powłoki.
Oto, jak ostatnio sobie z tym poradziłem w przypadku wielu bardzo dużych plików CSV, które analizowałem:
$ for file in *.csv; doecho"### ${file}" && head ${file} && echo ... && tail ${file} && echo; done
Spowoduje to wydrukowanie pierwszych 10 wierszy i ostatnich 10 wierszy każdego pliku, jednocześnie wypisując nazwę pliku i kilka wielokropków przed i po.
W przypadku jednego dużego pliku możesz po prostu uruchomić następujące polecenie, aby uzyskać ten sam efekt:
$ head somefile.csv && echo ... && tail somefile.csv
Odpowiedzi:
Możesz po prostu:
A jeśli z jakiegoś powodu potrzebujesz rur, to w ten sposób:
Uwaga: wydrukuje zduplikowane linie, jeśli liczba linii w pliku.txt jest mniejsza niż domyślne linie nagłówka + domyślne linie końca.
źródło
head
zużyciu pierwszych 10 wierszy pliku. (Porównaj to zhead < file.txt; tail < file.txt
plikiem zawierającym mniej niż 20 linii). Tylko bardzo drobna kwestia, o której należy pamiętać. (Ale wciąż +1.)head
tylko pierwsze 10 wierszy swojego wejścia, nie ma gwarancji, że nie zużywa go więcej w celu znalezienia końca dziesiątego wiersza, pozostawiając mniej wejścia do wyświetlenia.less
seq 100 | (head; tail)
daje mi tylko pierwsze 10 liczb. Tylko przy znacznie większym rozmiarze wejściowym (takim jakseq 2000
) ogon otrzymuje pewne dane wejściowe.ed
jeststandard text editor
$ echo -e '1+10,$-10d\n%p' | ed -s file.txt
źródło
sed
naed
W przypadku czystego strumienia (np. Wyjście z polecenia), możesz użyć „tee”, aby rozwidlić strumień i wysłać jeden strumień do głowy i jeden do końca. Wymaga to użycia funkcji '> (list)' w bash (+ / dev / fd / N):
lub używając / dev / fd / N (lub / dev / stderr) plus podpowłoki ze skomplikowanym przekierowaniem:
(Żadne z nich nie będzie działać w csh ani tcsh).
Aby uzyskać trochę lepszą kontrolę, możesz użyć tego polecenia perla:
COMMAND | perl -e 'my $size = 10; my @buf = (); while (<>) { print if $. <= $size; push(@buf, $_); if ( @buf > $size ) { shift(@buf); } } print "------\n"; print @buf;'
źródło
COMMAND | { tee >(head >&2) | tail; } |& other_commands
cat >/dev/null
naprawia to:COMMAND | { tee >(head >&2; cat >/dev/null) | tail; } |& other_commands
head
itail
: \ ...(sed -u 10q; echo ...; tail) < file.txt
Kolejna odmiana
(head;tail)
motywu, ale unikająca początkowego problemu z wypełnianiem bufora w przypadku małych plików.źródło
head -10 file.txt; tail -10 file.txt
Poza tym będziesz musiał napisać własny program / skrypt.
źródło
cat
i /head
lubtail
rurami, dobrze wiedzieć, że mogę ich używać indywidualnie!{ head file; tail file; } | prog
(wymagane są odstępy wewnątrz nawiasów klamrowych i końcowy średnik)Na podstawie komentarza JF Sebastiana :
W ten sposób możesz przetwarzać pierwszą linię i resztę inaczej w jednej rurze, co jest przydatne podczas pracy z danymi CSV:
{ echo N; seq 3;} | { tee >(head -n1 | sed 's/$/*2/' >&3; cat >/dev/null) | tail -n+2 | awk '{print $1*2}'; } 3>&1
źródło
Problem polega na tym, że programy zorientowane strumieniowo nie znają z wyprzedzeniem długości pliku (ponieważ może go nie być, jeśli jest to prawdziwy strumień).
narzędzia takie jak
tail
buforowanie ostatnich n widzianych wierszy i czekanie na koniec strumienia, a następnie drukowanie.jeśli chcesz to zrobić za pomocą jednego polecenia (i chcesz, aby działało z dowolnym przesunięciem i nie powtarzaj wierszy, jeśli się nakładają), będziesz musiał emulować to zachowanie, o którym wspomniałem.
spróbuj tego 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
źródło
a.out | awk -v ...
Skończyło się na tym rozwiązaniu, które wydaje się być jedynym, które obejmowało wszystkie przypadki użycia (do tej pory):
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]} }'
Lista funkcji:
źródło
Od jakiegoś czasu szukałem tego rozwiązania. Wypróbowałem to sam z sedem, ale problem braku znajomości długości pliku / strumienia był nie do pokonania. Ze wszystkich opcji dostępnych powyżej podoba mi się rozwiązanie awk Camille Goudeseune. Zanotował, że jego rozwiązanie pozostawiło dodatkowe puste wiersze na wyjściu z wystarczająco małym zestawem danych. Tutaj podaję modyfikację jego rozwiązania, która usuwa dodatkowe linie.
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] }' ; }
źródło
Cóż, zawsze możesz je połączyć. Tak jak tak
head fiename_foo && tail filename_foo
. Jeśli to nie wystarczy, możesz napisać sobie funkcję bash w swoim pliku .profile lub dowolnym pliku logowania, którego używasz:head_and_tail() { head $1 && tail $1 }
A później powołać go z powłoki wiersza:
head_and_tail filename_foo
.źródło
Pierwsze 10 wierszy pliku file.ext, a następnie jego ostatnie 10 wierszy:
cat file.ext | head -10 && cat file.ext | tail -10
Ostatnie 10 wierszy pliku, a następnie pierwsze 10:
cat file.ext | tail -10 && cat file.ext | head -10
Następnie możesz potokować wyjście również w innym miejscu:
(cat file.ext | head -10 && cat file.ext | tail -10 ) | your_program
źródło
tail
i /head
lub, tworząc jej alias.Napisałem prostą aplikację w Pythonie, aby to zrobić: https://gist.github.com/garyvdm/9970522
Obsługuje potoki (strumienie), a także pliki.
źródło
opierając się na powyższych pomysłach (przetestowane bash i zsh)
ale używając aliasu „hat” Head and Tails
alias hat='(head -5 && echo "^^^------vvv" && tail -5) < ' hat large.sql
źródło
Dlaczego nie użyć
sed
do tego zadania?sed -n -e 1,+9p -e 190,+9p textfile.txt
źródło
Aby obsłużyć potoki (strumienie), a także pliki, dodaj to do pliku .bashrc lub .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] }' ; }
Wtedy możesz nie tylko
ale również
(To nadal dodaje fałszywe puste wiersze, gdy 10 przekracza długość wejścia, w przeciwieństwie do zwykłego starego
a.out | (head; tail)
. Dziękuję, poprzednie osoby odpowiadające).Uwaga:
headtail 10
nieheadtail -10
.źródło
Opierając się na tym, co @Samus_ wyjaśnił tutaj o tym, jak działa polecenie @Aleksandra Zalcman, ta odmiana jest przydatna, gdy nie można szybko zlokalizować początku ogona bez liczenia linii.
{ head; echo "####################\n...\n####################"; tail; } < file.txt
Lub jeśli zaczniesz pracować z czymś innym niż 20 liniami, liczba linii może nawet pomóc.
źródło
Aby wydrukować pierwsze 10 i ostatnie 10 wierszy pliku, możesz spróbować tego:
cat <(head -n10 file.txt) <(tail -n10 file.txt) | less
źródło
sed -n "1,10p; $(( $(wc -l ${aFile} | grep -oE "^[[:digit:]]+")-9 )),\$p" "${aFile}"
UWAGA : Zmienna aFile zawiera pełną ścieżkę do pliku .
źródło
Powiedziałbym, że w zależności od rozmiaru pliku, aktywne czytanie jego zawartości może nie być pożądane. W takiej sytuacji myślę, że wystarczy prosty skrypt powłoki.
Oto, jak ostatnio sobie z tym poradziłem w przypadku wielu bardzo dużych plików CSV, które analizowałem:
$ for file in *.csv; do echo "### ${file}" && head ${file} && echo ... && tail ${file} && echo; done
Spowoduje to wydrukowanie pierwszych 10 wierszy i ostatnich 10 wierszy każdego pliku, jednocześnie wypisując nazwę pliku i kilka wielokropków przed i po.
W przypadku jednego dużego pliku możesz po prostu uruchomić następujące polecenie, aby uzyskać ten sam efekt:
$ head somefile.csv && echo ... && tail somefile.csv
źródło
Zużywa stdin, ale jest prosty i działa w 99% przypadków użycia
head_and_tail
#!/usr/bin/env bash COUNT=${1:-10} IT=$(cat /dev/stdin) echo "$IT" | head -n$COUNT echo "..." echo "$IT" | tail -n$COUNT
przykład
źródło