Jak czytać pierwszy i ostatni wiersz z wyjścia kota?

64

Mam plik tekstowy. Zadanie - pobierz pierwszy i ostatni wiersz z pliku po

$ cat file | grep -E "1|2|3|4" | commandtoprint

$ cat file
1
2
3
4
5

Potrzebujesz tego bez wyjścia kota (tylko 1 i 5).

~$ cat file | tee >(head -n 1) >(wc -l)
1
2
3
4
5
5
1

Może istnieje awk i krótsze rozwiązanie ...

dmgl
źródło
W drugim przykładzie wc -lnie ma nic wspólnego z wypisaniem ostatniego wiersza pliku.
David Richerby

Odpowiedzi:

115

Rozwiązanie sed :

sed -e 1b -e '$!d' file

Podczas czytania z stdinif wyglądałby tak (na przykład ps -ef):

ps -ef | sed -e 1b -e '$!d'
UID        PID  PPID  C STIME TTY          TIME CMD
root      1931  1837  0 20:05 pts/0    00:00:00 sed -e 1b -e $!d

Rozwiązanie głowa i ogon :

(head -n1 && tail -n1) <file

Gdy dane pochodzą z polecenia ( ps -ef):

ps -ef 2>&1 | (head -n1 && tail -n1)
UID        PID  PPID  C STIME TTY          TIME CMD
root      2068  1837  0 20:13 pts/0    00:00:00 -bash

awk Rozwiązanie:

awk 'NR==1; END{print}' file

A także potokowy przykład z ps -ef:

ps -ef | awk 'NR==1; END{print}'
UID        PID  PPID  C STIME TTY          TIME CMD
root      1935  1837  0 20:07 pts/0    00:00:00 awk NR==1; END{print}
chaos
źródło
1
Dziękuję Ci! To najlepsza odpowiedź, ponieważ nie mogę tego zrobić. (head -n1 file;tail -n1 file)Mam bardzo duże polecenie i potok jako ostatni symbol. Taki | sed '1p;$!d'krótszy.
dmgl,
Przepraszam za mój angielski, jeśli mnie nie rozumiesz - to mój problem - powiedz mi o tym, a ja przygotuję dla Ciebie lepszą prezentację.
dmgl
7
Czy to head && tailnaprawdę działa dla ciebie? seq 10 | (head -n1 && tail -n1)drukuje 1tylko.
glenn jackman
1
@DavidConrad, aby rozwinąć to, co powiedział chaos, -e 1b- w pierwszym wierszu przejdź do końca skryptu sed, w którym to momencie następuje niejawne „drukowanie”. Jeśli wejście ma tylko jedną linię, sed kończy się. W przeciwnym razie dla wszystkich wierszy oprócz ostatniego usuń. W ostatnim wierszu niejawne „drukowanie” zdarza się ponownie.
glenn jackman
1
@mikeserv: ;-) sprawdź, kiedy masz szansę. W pojedynczym wierszu skutecznie zapobiega podwojeniu go na wyjściu, ale w przypadku wieloliniowego przypadku, po prostu zachowuje ostatni wiersz ... przynajmniej w GNU sed4.2.2. Twoje zdrowie.
Cbhihe,
23

sed -n '1p;$p' file.txt wypisze pierwszy i ostatni wiersz pliku.txt.

schaiba
źródło
10
Zauważ, że jeśli wejście ma tylko jedną linię, zostanie wydrukowane dwukrotnie. Możesz preferować, sed -e 1b -e '$!d'jeśli tego nie chcesz.
Stéphane Chazelas
10

Zabawny czysty Bash ≥4 sposób:

cb() { (($1-1>0)) && unset "ary[$1-1]"; }
mapfile -t -C cb -c 1 ary < file

Następnie otrzymasz tablicę aryz pierwszym polem (tj. Z indeksem 0) będącym pierwszą linią file, a ostatnim polem jest ostatnia linia file. Wywołanie zwrotne cb(opcja jeśli chcesz slurp wszystkie wiersze w tablicy) unsets wszystkie linie pośrednie, tak aby nie zaśmiecać pamięć. Jako darmowy produkt uboczny będziesz mieć także liczbę wierszy w pliku (jako ostatni indeks tablicy + 1).

Próbny:

$ mapfile -t -C cb -c 1 ary < <(printf '%s\n' {a..z})
$ declare -p ary
declare -a ary='([0]="a" [25]="z")'
$ # With only one line
$ mapfile -t -C cb -c 1 ary < <(printf '%s\n' "only one line")
$ declare -p ary
declare -a ary='([0]="only one line")'
$ # With an empty file
$ mapfile -t -C cb -c 1 ary < <(:)
declare -a ary='()'
gniourf_gniourf
źródło
7

Z sedmożna dsuĹ linie jeśli NIE1 st jeden I NIE La $jeden t.
Służy !do NOT(negowania) warunku i X{Y..}konstrukcji do łączenia warunków X AND Y :

cmd | sed '1!{$!d;}'

lub możesz użyć zakresu - od 2nd do la $t - i usunąć wszystkie linie z tego zakresu oprócz linii la $t:

cmd | sed '2,${$!d;}'
don_crissti
źródło
6

Za pomocą Perla:

$ seq 10 |  perl -ne 'print if 1..1 or eof'
1
10

Powyżej drukuje pierwszy element na wyjściu seq 10przez if 1..1, natomiast or eofdrukuje również ostatni element.

perlygatekeeper
źródło
3
Czy możesz wyjaśnić, jak to działa? Unikaj udzielania takich jednoznacznych odpowiedzi bez wyjaśnienia, co robią i jak.
terdon
1
co trzeba /etc abrti yum.repos.dtrzeba zrobić to pytanie?
drs
@drs Zredagowałem odpowiedź, aby uniknąć użycia „ls” jako przykładowego wejścia.
dolmen
1
@dolmen: może być dobrym pomysłem, aby zakończyć edycję, pomijając wszelkie odniesienia do / etc. Wydaje mi się, że taki został dodany po pierwszej edycji, ale mimo wszystko odpowiedź nie ma sensu. Tylko sugestia.
Cbhihe,
4

Bez kota:

$ cat file |tee >(head -n1) >(tail -n1) >/dev/null
1
5

lub

$ (head -n1 file;tail -n1 file)
1
5

źródło
8
W pierwszym kolejności kolejność linii nie jest gwarantowana.
Stéphane Chazelas
4
$ seq 100 | { IFS= read -r first; echo "$first"; tail -1; }
1
100
Glenn Jackman
źródło