Đối diện đuôi: tất cả các dòng trừ n dòng cuối cùng


36

Làm cách nào tôi có thể loại bỏ n dòng cuối cùng của tệp bằng bộ lọc dòng lệnh unix?

Điều đó sẽ trái ngược với tail: tailloại bỏ n dòng đầu tiên nhưng bỏ phần còn lại qua, nhưng tôi muốn lệnh chuyển mọi thứ qua trừ n dòng cuối cùng.

Thật không may, tôi đã không tìm thấy bất cứ điều gì như vậy - cũng headkhông giúp được gì. EDIT : Ít nhất là trong Solaris, nó không có những tranh luận tiêu cực.

Cập nhật: Tôi chủ yếu quan tâm đến một giải pháp hoạt động cho các tệp lớn, tức là logfiles, nơi bạn có thể muốn kiểm tra những gì đã xảy ra trong những phút cuối.


FYI khi sử dụng head: Bằng cách đặt '-' trước số với tùy chọn -n, nó sẽ in tất cả các dòng của mỗi tệp nhưng không phải là N dòng cuối cùng như hiển thị bên dưới,
G Koe

Câu trả lời:


38

Nếu bạn có GNU head, bạn có thể sử dụng

head -n -5 file.txt

để in tất cả trừ 5 dòng cuối cùng của file.txt.

Nếu head -nkhông có đối số phủ định, hãy thử

head -n $(( $(wc -l file.txt | awk '{print $1}') - 5 )) file.txt

11
(và cầu nguyện file.txtdài ít nhất sáu dòng ...)
một CVn

1
Đáng buồn thay, phiên bản không phải GNU này cũng không hoạt động với các luồng
Armand

1
@ MichaelKjorling Ít nhất là trên Ubuntu, đó không phải là vấn đề. Nếu các tệp có ít dòng hơn được chỉ định trong head, một đầu ra trống được trả về, không có lỗi.
Alphaaa

Nếu tôi không nhầm đầu -n 5 sẽ in 5 dòng đầu tiên, không phải tất cả, ngoại trừ 5 dòng cuối ...
pypmannetjies

8
head file.txt               # first 10 lines
tail file.txt               # last 10 lines
head -n 20 file.txt         # first 20 lines
tail -n 20 file.txt         # last 20 lines
head -20 file.txt           # first 20 lines
tail -20 file.txt           # last 20 lines
head -n -5 file.txt         # all lines except the 5 last
tail -n +5 file.txt         # all lines except the 4 first, starts at line 5

1
Điều này thêm gì mà không được trả lời trong câu trả lời được chấp nhận? Ngoài ra, như với các câu trả lời khác của bạn, một vài dòng giải thích về câu trả lời của bạn sẽ cải thiện đáng kể nó.
nhạc2myear

1
tóm tắt rất tốt
ruanhao

5

Đây là một cách đơn giản để xóa dòng cuối cùng, hoạt động trên BSD, v.v.

sed '$d' input.txt

Biểu thức ghi "trên dòng cuối cùng, xóa nó". Các dòng khác sẽ được in, vì đó là sedhành vi mặc định.

Bạn có thể xâu chuỗi chúng lại với nhau để loại bỏ nhiều dòng

sed '$d' input.txt | sed '$d' | sed '$d'

Đó là một chút nặng tay, thừa nhận, nhưng chỉ quét một lần qua các tập tin.

Bạn cũng có thể xem cái này, để biết thêm câu trả lời: https://stackoverflow.com/questions/13380607/how-to-use-sed-to-remove-last-n-lines-of-a-file

Đây là một lớp lót được điều chỉnh từ một trong những mục yêu thích của tôi ở đó:

N=10
sed -n -e ':a' -e "1,$N!{P;N;D;};N;ba"

Tôi đã vui vẻ giải mã cái đó và tôi cũng hy vọng bạn cũng vậy (: Nó thực hiện Ncác dòng đệm khi quét, nhưng nếu không thì khá hiệu quả.


3

Tôi tò mò tại sao bạn nghĩ headkhông phải là một lựa chọn:

~$ man head
...
-n, --lines=[-]K
        print the first K lines instead of the first 10; 
        with the leading `-', print all but the last K lines of each file

Điều này dường như phù hợp với mục đích của bạn, sử dụng, ví dụ:

head -n -20 yourfile.txt

5
Lưu ý rằng điều này chỉ áp dụng cho GNU head. BSD headkhông có tùy chọn này, vì vậy câu trả lời này sẽ không hoạt động trên Solaris hoặc các Unix khác mà không có lõi GNU. OP cũng đặc biệt gắn thẻ này với Unix và Unix-Utils.
slhck

2
@slhck Chưa kể đến việc OP đề cập rằng đây là dành cho Solaris.
một CVn

Thật không may, ai đó đã loại bỏ đề cập của tôi về Solaris. Nhưng dù sao tôi cũng nên đề cập rằng phiên bản đầu không hỗ trợ điều đó.
Hans-Peter Störr

1
Xin lỗi tất cả. Tôi không chú ý đến Solaris, tôi cũng không biết về các phiên bản đầu khác nhau.
Anders R. Bystrup

1
@hstoerr Solaris hiện có trong thẻ của bạn :)
slhck

0

Một cách khác để làm điều đó nếu tail -nkhông có lý lẽ tiêu cực là

tac file.txt | tail -n +6 | tac

Điều này sẽ loại bỏ 5 dòng cuối cùng


Cảm ơn! Đó là một ý tưởng tiện lợi cho đến nay không ai nghĩ ra. Thật không may, điều đó sẽ không hiệu quả đối với usecase mà tôi có trong đầu với câu hỏi này: nếu đó là một tệp lớn, nó sẽ không chỉ được đọc hoàn toàn qua một hoặc nhiều lần, như với các giải pháp khác, mà có lẽ nó cũng sẽ được viết cho đĩa vào tệp tạm thời bằng tac nếu nó không vừa với bộ nhớ.
Hans-Peter Störr

@ Hans-Peter Rất đúng. Quyết định viết một kịch bản python3 cho nó. Hãy thử github.com/atw31337/donkey này . Tôi khuyên bạn nên sử dụng các tùy chọn đầu ra. Họ chạy nhanh hơn nhiều so với sử dụng chuyển hướng.
atw31337

Viết độc đáo! Tuy nhiên, nó đọc qua tệp hai lần, điều này không thực sự cần thiết nếu bạn đệm n dòng cuối cùng và đây là vấn đề trên các tệp lớn. Cá nhân, tôi không cần điều đó nữa, nhưng trong trường hợp bạn vui vẻ cải thiện nó và những người khác cần điều đó ... Rốt cuộc, có một vài lượt thích và đánh dấu vào câu hỏi.
Hans-Peter Störr

@ Hans-Peter. Kích thước bộ đệm sẽ phụ thuộc vào số lượng dòng cần loại bỏ. Đây có thể là một vấn đề nếu một số lượng rất lớn các dòng cần phải được loại bỏ khỏi tệp. Để tránh các vấn đề liên quan đến bộ nhớ, tôi viết lại tập lệnh sử dụng phương thức đếm dòng có giá trị n cao và phương thức đệm có giá trị n thấp hơn; tuy nhiên, sau khi thử nghiệm nó trên một tệp rất lớn, phương pháp đếm dòng ban đầu vẫn nhanh hơn. Có vẻ như chi phí quản lý bộ đệm vượt trội hơn tổng số dòng trên đầu ... hoặc tôi chỉ thiếu một cái gì đó.
atw31337

Đẹp, nhưng đối với Mac OS X biến thể BSD theo mặc định, không có lệnh tac. :( Loại này đánh bại trường hợp sử dụng.
ingyhere
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.