Bagaimana cara membaca baris pertama dan terakhir dari keluaran kucing?

64

Saya punya file teks. Tugas - dapatkan baris pertama dan terakhir dari file setelah

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

$ cat file
1
2
3
4
5

Perlu ini tanpa keluaran cat (hanya 1 dan 5).

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

Mungkin ada solusi yang lebih canggung dan lebih pendek ...

dmgl
sumber
Dalam contoh kedua Anda, wc -ltidak ada hubungannya dengan mengeluarkan baris terakhir file.
David Richerby

Jawaban:

115

Solusi sed :

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

Saat membaca dari stdinapakah akan terlihat seperti ini (misalnya 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

Solusi kepala & ekor :

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

Saat data berasal dari perintah ( 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

Solusi awk :

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

Dan juga contoh pipa dengan 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}
kekacauan
sumber
1
Terima kasih! Ini jawaban terbaik karena saya tidak bisa melakukan (head -n1 file;tail -n1 file)saya memiliki perintah dan pipa yang sangat besar sebagai simbol terakhir. Jadi | sed '1p;$!d'lebih pendek.
dmgl
Maaf untuk bahasa Inggris saya, jika Anda tidak mengerti saya - ini masalah saya - ceritakan tentang hal itu dan saya persiapkan presentasi yang lebih baik untuk Anda.
dmgl
7
Apakah ini head && tailbenar-benar bekerja untuk Anda? hanya seq 10 | (head -n1 && tail -n1)mencetak 1.
glenn jackman
1
@ Davidvidon, untuk menguraikan apa yang dikatakan kekacauan, -e 1b- pada baris pertama, cabang ke ujung skrip sed, di mana titik "cetak" implisit terjadi. Jika input hanya satu baris, sed berakhir. Kalau tidak, untuk semua baris kecuali yang terakhir, hapus. Pada baris terakhir, "cetak" implisit terjadi lagi.
glenn jackman
1
@ mikeserv: ;-) periksa ketika Anda mendapatkan kesempatan. Pada satu baris ia secara efektif mencegah penggandaan pada keluaran, tetapi pada beberapa kasus work-line, ini hanya mempertahankan baris terakhir ... setidaknya pada GNU sed4.2.2. Tepuk tangan.
Cbhihe
23

sed -n '1p;$p' file.txt akan mencetak baris pertama dan terakhir dari file.txt.

schaiba
sumber
10
Perhatikan bahwa jika input hanya memiliki satu baris, itu akan dicetak dua kali. Anda dapat memilih sed -e 1b -e '$!d'jika Anda tidak menginginkannya.
Stéphane Chazelas
10

Cara Bash≥4 murni yang lucu:

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

Setelah ini, Anda akan memiliki array arydengan bidang pertama (yaitu, dengan indeks 0) menjadi baris pertama file, dan bidang terakhir menjadi baris terakhir file. Callback cb(opsional jika Anda ingin menghirup semua baris dalam array) menghapus semua garis tengah agar tidak mengacaukan memori. Sebagai produk sampingan gratis, Anda juga akan memiliki jumlah baris dalam file (sebagai indeks terakhir array +1).

Demo:

$ 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
sumber
7

Dengan sedAnda bisa dmenghapus garis jika BUKAN yang 1pertama DAN BUKAN yang $satu.
Gunakan !untuk NOT(meniadakan) suatu kondisi dan X{Y..}konstruk untuk menggabungkan kondisi X AND Y :

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

atau Anda dapat menggunakan rentang - dari 2nd ke la $t - dan menghapus semua baris dalam rentang itu kecuali baris la $t:

cmd | sed '2,${$!d;}'
don_crissti
sumber
6

Menggunakan Perl:

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

Di atas mencetak item pertama dalam output seq 10via if 1..1, sedangkan or eofjuga akan mencetak item terakhir.

perlygatekeeper
sumber
3
Bisakah Anda menjelaskan cara kerjanya? Harap hindari memberikan jawaban satu garis seperti itu tanpa penjelasan tentang apa yang mereka lakukan dan bagaimana.
terdon
1
apa yang harus /etc abrtdan yum.repos.dharus dilakukan pertanyaan ini?
drs
@ drs Saya mengedit jawaban untuk menghindari penggunaan 'ls' sebagai input sampel.
dolmen
1
@dolmen: mungkin ide yang bagus untuk menyelesaikan pengeditan dengan menekan semua referensi ke / etc. Saya kira seperti itu ditambahkan setelah edit pertama Anda, tetapi, semua sama, karena jawabannya tidak masuk akal sama sekali. Hanya sebuah saran.
Cbhihe
4

Tanpa kucing:

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

atau

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

sumber
8
Pada yang pertama, urutan garis tidak dijamin.
Stéphane Chazelas
4
$ seq 100 | { IFS= read -r first; echo "$first"; tail -1; }
1
100
glenn jackman
sumber