Làm thế nào để đọc dòng đầu tiên và cuối cùng từ đầu ra mèo?


64

Tôi có tập tin văn bản. Nhiệm vụ - nhận dòng đầu tiên và dòng cuối cùng từ tệp sau

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

$ cat file
1
2
3
4
5

Cần điều này mà không có đầu ra mèo (chỉ 1 và 5).

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

Có lẽ awk và giải pháp ngắn hơn tồn tại ...


Trong ví dụ thứ hai của bạn, wc -lkhông có gì để làm với việc xuất dòng cuối cùng của tệp.
David Richerby

Câu trả lời:


115

Giải pháp sed :

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

Khi đọc từ stdinif sẽ trông như thế này (ví dụ 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

Giải pháp đầu & đuôi :

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

Khi dữ liệu đến từ một lệnh ( 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

Giải pháp awk :

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

Và cũng là ví dụ đường ống với 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}

1
Cảm ơn bạn! Đó là câu trả lời tốt nhất bởi vì tôi không thể có (head -n1 file;tail -n1 file)lệnh và đường ống rất lớn làm biểu tượng cuối cùng. Vì vậy, | sed '1p;$!d'ngắn hơn một.
dmgl

Xin lỗi vì tiếng Anh của tôi, nếu bạn không hiểu tôi - đó là vấn đề của tôi - hãy nói cho tôi biết về nó và tôi chuẩn bị bài thuyết trình tốt hơn cho bạn.
dmgl

7
head && tailthực sự làm việc cho bạn? chỉ seq 10 | (head -n1 && tail -n1)in 1.
glenn jackman

1
@DavidConrad, để giải thích về những gì hỗn loạn đã nói, -e 1b- trên dòng đầu tiên, nhánh đến cuối tập lệnh sed, tại thời điểm "in" ngầm xảy ra. Nếu đầu vào chỉ dài một dòng, sed kết thúc. Mặt khác, đối với tất cả các dòng ngoại trừ cuối cùng, xóa. Trên dòng cuối cùng, "in" ngầm xảy ra một lần nữa.
glenn jackman

1
@mikeerv: ;-) kiểm tra nó khi bạn có cơ hội. Trên một dòng duy nhất, nó hoàn toàn ngăn chặn việc nhân đôi nó trên đầu ra, nhưng trong trường hợp công việc nhiều dòng, nó chỉ bảo toàn dòng cuối cùng ... ít nhất là trên GNU sed4.2.2. Chúc mừng.
Cbhihe

23

sed -n '1p;$p' file.txt sẽ in dòng đầu tiên và cuối cùng của file.txt.


10
Lưu ý rằng nếu đầu vào chỉ có một dòng, nó sẽ được in hai lần. Bạn có thể thích sed -e 1b -e '$!d'nếu bạn không muốn điều đó.
Stéphane Chazelas

10

Một cách Bash4 thuần túy hài hước:

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

Sau này, bạn sẽ có một mảng aryvới trường đầu tiên (nghĩa là với chỉ mục 0) là dòng đầu tiên filevà trường cuối cùng của nó là dòng cuối cùng file. Cuộc gọi lại cb(tùy chọn nếu bạn muốn ẩn tất cả các dòng trong mảng) bỏ cài đặt tất cả các dòng trung gian để không làm lộn xộn bộ nhớ. Là sản phẩm phụ miễn phí, bạn cũng sẽ có số lượng dòng trong tệp (là chỉ mục cuối cùng của mảng + 1).

Bản giới thiệu:

$ 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='()'

7

Với sedbạn có thể bỏ qua dcác dòng nếu KHÔNG phải1thứ nhất VÀ KHÔNG phải là dòng thứ $nhất.
Sử dụng !để NOT(phủ định) một điều kiện và X{Y..}cấu trúc để kết hợp các điều kiện X AND Y :

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

hoặc bạn có thể sử dụng một phạm vi - từ 2nd đến la $t - và xóa tất cả các dòng trong phạm vi đó ngoại trừ dòng la $t:

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

6

Sử dụng Perl:

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

Ở trên in mục đầu tiên trong đầu ra của seq 10thông qua if 1..1, trong khi đó or eofcũng sẽ in mục cuối cùng.


3
Bạn có thể giải thích làm thế nào điều này hoạt động? Xin vui lòng tránh đưa ra câu trả lời một lót như vậy mà không có lời giải thích về những gì họ làm và làm thế nào.
terdon

1
Làm gì /etc abrtyum.repos.dphải làm câu hỏi này?
DRS

@drs Tôi đã chỉnh sửa câu trả lời để tránh sử dụng 'ls' làm đầu vào mẫu.
heo

1
@dolmen: có thể là một ý tưởng tốt để hoàn thành chỉnh sửa bằng cách bỏ qua tất cả các tham chiếu đến / etc. Tôi đoán như vậy đã được thêm vào sau lần chỉnh sửa đầu tiên, nhưng, tất cả đều giống nhau, vì nó là câu trả lời không có ý nghĩa gì cả. Chỉ là một gợi ý.
Cbhihe

4

Không có mèo:

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

hoặc là

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

8
Trong cái đầu tiên, thứ tự của các dòng không được đảm bảo.
Stéphane Chazelas

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.