Làm cách nào để hiển thị một số dòng nhất định từ tệp văn bản trong Linux?


85

Tôi đoán mọi người đều biết các tiện ích dòng cmd hữu ích của Linux headtail. headcho phép bạn in các dòng X đầu tiên của tệp, tailthực hiện tương tự nhưng in phần cuối của tệp. Một lệnh tốt để in giữa một tập tin là gì? một cái gì đó giống như middle --start 10000000 --count 20(in dòng thứ 10.000 đến năm thứ 10 đến năm thứ 10).

Tôi đang tìm kiếm thứ gì đó sẽ xử lý các tệp lớn một cách hiệu quả. Tôi đã thử tail -n 10000000 | head 10và nó chậm kinh khủng.


5
bản sao có thể có của serverfault.com/questions/101900/ Mạnh
Kyle Brandt

Câu trả lời:


111
sed -n '10000000,10000020p' filename

Bạn có thể tăng tốc một chút như thế này:

sed -n '10000000,10000020p; 10000021q' filename

Trong các lệnh đó, tùy chọn -ngây ra sed"triệt tiêu tự động in không gian mẫu". Các plệnh "in [s] không gian mô hình hiện tại" và qlệnh "Ngay lập tức bỏ [s] kịch bản sed mà không xử lý bất kỳ đầu vào hơn ..." Các dấu ngoặc kép là từ sed mantrang .

Nhân tiện, lệnh của bạn

tail -n 10000000 filename | head 10

bắt đầu ở dòng mười phần triệu từ cuối tệp, trong khi lệnh "giữa" của bạn dường như bắt đầu ở phần mười triệu từ đầu , tương đương với:

head -n 10000010 filename | tail 10

Vấn đề là đối với các tệp chưa được sắp xếp với các dòng có độ dài thay đổi, bất kỳ quá trình nào cũng sẽ phải trải qua các tập tin đếm dòng mới. Không có cách nào để tắt nó.

Tuy nhiên, nếu tệp được sắp xếp (ví dụ: tệp nhật ký có dấu thời gian) hoặc có các dòng có độ dài cố định, thì bạn có thể tìm kiếm tệp dựa trên vị trí byte. Trong ví dụ về tệp nhật ký, bạn có thể thực hiện tìm kiếm nhị phân trong một khoảng thời gian như tập lệnh Python của tôi ở đây *. Trong trường hợp tệp có độ dài bản ghi cố định, nó thực sự dễ dàng. Bạn chỉ cần tìm kiếm các linelength * linecountký tự vào tập tin.

* Tôi giữ ý nghĩa để đăng một bản cập nhật khác cho kịch bản đó. Có lẽ tôi sẽ đi xung quanh nó một trong những ngày này.


Đây là sedphiên bản của middlechức năng của Charles : middle() { local s=$1 c=$2; shift 2; sed -n "$s,$(($s + $c -1))p; $(($s + $c))q" "$@"; }. Nó sẽ xử lý nhiều đối số tệp, tên tệp có khoảng trắng, v.v ... Nhiều tệp được xử lý cùng nhau như thể chúng đã được xử lý theo cùng một cách sedthông thường (vì vậy, giữa 100 100 tệp1 tệp2 sẽ trải dài từ cuối tệp đầu tiên đến đầu tệp của cái thứ hai nếu cái thứ nhất có ít hơn 1100 dòng).
Dennis Williamson

Hàm trong nhận xét trước của tôi có thể được gọi với tham số tên tệp: middle startline count filenamehoặc nhiều tên tệp: middle startline count file1 file2 file3hoặc với chuyển hướng: middle startline count < filenamehoặc trong một đường ống: some_command | đếm giữa dòng bắt đầu `hoặccat file* | middle startline count
Dennis Williamson

Không phải `trong lệnh sed của bạn là '? Tôi không thể làm cho nó hoạt động với backtick nhưng nó hoạt động tốt với một trích dẫn.
Ian Hunter

@beanland: Vâng, đó là một lỗi đánh máy. Tôi đã sửa nó. Cảm ơn.
Dennis Williamson

1
@kev: Tôi đã thêm một số lời giải thích cho câu trả lời của tôi.
Dennis Williamson

28

Tôi phát hiện ra việc sử dụng sau đây của sed

sed -n '10000000,+20p'  filename

Hy vọng nó hữu ích cho ai đó!


Điều tốt để biết rằng có một sự thay thế cho đối số dòng cuối cùng được đề xuất bởi Dennis: một dòng được tính là sed -nđối số thứ hai làm cho nó khá dễ đọc.
user3123159

Một ví dụ sử dụng: extract_lines(){sed -n "$1,+$2p" <file>}ghi vào thiết bị xuất chuẩn.
user3123159

4

Đây là lần đầu tiên tôi đăng bài ở đây! Dù sao, điều này là dễ dàng. Giả sử bạn muốn kéo dòng 8872 từ tệp của mình có tên là file.txt. Đây là cách bạn làm điều đó:

tập tin con mèo | grep '^ * 8872'

Bây giờ câu hỏi là tìm 20 dòng sau này. Để thực hiện điều này bạn làm

tập tin con mèo | grep -A 20 '^ * 8872'

Đối với các dòng xung quanh hoặc trước khi xem các cờ -B và -C trong hướng dẫn grep.


Mặc dù điều đó đúng về mặt kỹ thuật và là một cách thú vị để thực hiện nó trên một tệp có kích thước hợp lý, tôi tò mò về hiệu quả của nó khi làm việc với các tệp có kích thước mà người đăng đang hỏi.
Jenny D

Nhiều dòng: cat -n file.txt | grep "^ \ s \ + (10 \ | 20 \ | 30) \ s \ +"
Jeffrey Knight

cat -n file.txt | grep '^ *1'mang lại tất cả các dòng có 1 ở bên phải của chúng. Làm thế nào để đầu ra dòng 1 với kỹ thuật này? Tôi biết tôi có thể đứng đầu -n 1 .... nhưng làm thế nào để sử dụng grep?
Sean87

1

Câu trả lời của Dennis là con đường để đi. Nhưng chỉ sử dụng đầu & đuôi, dưới bash:

middle () {head -n $ [$ 1 + $ 2] | đuôi -n $ 2; }

Điều này quét các dòng $ 1 + $ 2 đầu tiên hai lần, vì vậy tệ hơn nhiều so với câu trả lời của Dennis. Nhưng bạn không cần phải nhớ tất cả những chữ cái sed để sử dụng nó ....


Sử dụng $[...]bị phản đối, ít nhất là trong Bash. Ngoài ra, bạn đang thiếu một tham số tệp.
Dennis Williamson

@Dennis: Không thiếu tham số: bạn có nghĩa là sử dụng điều này trên stdin, theo middle 10 10 < /var/log/auth.log.
Charles Stewart

1

Sử dụng lệnh sau để có được phạm vi cụ thể của dòng

awk 'NR < 1220974{next}1;NR==1513793{exit}' debug.log | tee -a test.log

Ở đây debug.log là tệp của tôi bao gồm thiếu các dòng và tôi đã sử dụng để in các dòng từ số dòng 1220974 đến 1513793 sang tệp test.log. hy vọng nó sẽ hữu ích cho việc nắm bắt phạm vi của các dòng.


Câu trả lời tương tự như serverfault.com/a/641252/140016 . Bị hạ bệ.
Deer Hunter

Nó không phải là cùng một câu trả lời. Điều này sẽ nhanh hơn đối với các tệp lớn vì nó thực sự hủy bỏ sau khi in dòng cuối cùng thay vì tiếp tục quét qua tệp.
phobic

0

Một phiên bản oneliner ruby.

ruby -pe 'next unless $. > 10000000 && $. < 10000020' < filename.txt

Nó có thể hữu ích cho ai đó. Các giải pháp với 'sed' được cung cấp bởi Dennis và Dox là rất tốt, thậm chí vì nó có vẻ nhanh hơn.


0

Bạn có thể sử dụng 'nl'.

nl filename | grep <line_num>

0

Chẳng hạn, awk này sẽ in các dòng từ 20 đến 40

awk '{if ((NR> 20) && (NR <40)) in $ 0}' / etc / passwd


0

Nếu bạn biết các số dòng, giả sử bạn muốn lấy dòng 1, 3 và 5 từ một tệp, hãy nói / etc / passwd:

perl -e 'while(<>){if(++$l~~[1,3,5]){print}}' < /etc/passwd

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.