Lệnh unix nhanh để hiển thị các dòng cụ thể ở giữa một tệp?


206

Cố gắng gỡ lỗi một vấn đề với máy chủ và tệp nhật ký duy nhất của tôi là tệp nhật ký 20 GB (thậm chí không có dấu thời gian! Tại sao mọi người sử dụng System.out.println()làm nhật ký? Trong sản xuất?!)

Sử dụng grep, tôi đã tìm thấy một khu vực của tệp mà tôi muốn xem, dòng 347340107.

Khác với việc làm một cái gì đó như

head -<$LINENUM + 10> filename | tail -20 

... sẽ yêu cầu headđọc qua 347 triệu dòng đầu tiên của tệp nhật ký, có một lệnh nhanh chóng và dễ dàng có thể chuyển các dòng 347340100 - 347340200 (ví dụ) sang bàn điều khiển không?

cập nhật Tôi hoàn toàn quên rằng grep có thể in bối cảnh xung quanh một trận đấu ... điều này hoạt động tốt. Cảm ơn!


Tôi sẽ tưởng tượng grep phải tìm kiếm toàn bộ tập tin phải có một cách ít chuyên sâu hơn để làm điều này.
ojblass

Câu trả lời:


69

với GNU-grep bạn chỉ có thể nói

grep - liên kết = 10 ...

7
Hay cụ thể hơn là 10 dòng trước: grep -B 10 ... Hoặc 10 dòng sau: grep -A 10 ...
Cậu bé Baukema

17
Lệnh này không hoạt động, bên dưới sed -n '<start>, <end> p' đang hoạt động
Basav

5
Đây thực sự không phải là những gì bạn muốn bởi vì nó sẽ xử lý toàn bộ tập tin ngay cả khi trận đấu nằm ở bit trên cùng. Tại thời điểm này, một kết hợp đầu / đuôi hoặc đuôi / đầu hiệu quả hơn nhiều.
Sklivvz

3
Điều này hoàn toàn không thỏa mãn câu hỏi được hỏi vì điều này không cung cấp một cách để xuất ra một dòng cụ thể , như đã hỏi.
Chris Rasys

1
Đây không thực sự là những gì được yêu cầu. @matt b, tại sao bạn không chấp nhận câu trả lời này?
1271772

390

Tôi đã tìm thấy hai giải pháp khác nếu bạn biết số dòng nhưng không có gì khác (không thể có grep):

Giả sử bạn cần dòng 20 đến 40,

sed -n '20,40p;41q' file_name

hoặc là

awk 'FNR>=20 && FNR<=40' file_name

6
+1: Mặc dù bạn có thể muốn thoát sau khi in. Có thể cung cấp một số lợi ích hiệu suất nếu tập tin thực sự rất lớn.
jaypal singh

awk 'NR> = 20 && NR <= 40' file_name
Sudipta Basak

2
sed -n '20, 40p; 41q 'file_name để thoát sau đó.
Snigdha Batra 4/11/2015

1
cụ thể, đó là những số dòng bắt đầu và kết thúc. Nếu bạn đang ở trong một tệp lớn hơn, nó sẽ là '12345678,12345699p'
Mã số mẫu mã

1
Ngoài ra, để bình luận của @ CodeAbominator 41qhướng dẫn sed thoát khỏi dòng 41.
Brice

116
# print line number 52
sed -n '52p' # method 1
sed '52!d' # method 2
sed '52q;d' # method 3,  efficient on large files 

phương pháp 3 hiệu quả trên các tệp lớn

cách nhanh nhất để hiển thị các dòng cụ thể


Tôi đang cố gắng tìm ra cách thích ứng phương pháp 3 để sử dụng một phạm vi thay vì một dòng duy nhất, nhưng tôi sợ sed-foo của tôi không hoàn thành nhiệm vụ.
Xiong Chiamiov

9
@XiongChiamiov Làm thế nào về sed -n '1.500p; 501q' để in 1-500?
Sam

3
Lý do hai dòng / phương thức đầu tiên kém hiệu quả hơn là vì chúng tiếp tục xử lý tất cả các dòng sau Dòng 52, cho đến hết, trong khi # 3 dừng sau khi in Dòng 52.
Flow2k

1
Câu trả lời này sẽ có lợi từ việc giải thích những gì tất cả các đối số làm.
Bram Vanroy

25

Không, không có, các tập tin không có địa chỉ dòng.

Không có cách liên tục để tìm điểm bắt đầu của dòng n trong tệp văn bản. Bạn phải truyền qua tệp và đếm dòng mới.

Sử dụng công cụ đơn giản / nhanh nhất bạn có để thực hiện công việc. Đối với tôi, sử dụng headlàm cho nhiều ý nghĩa hơn grep, vì sau này là phức tạp cách hơn. Tôi không nói " grepchậm", thực sự không phải vậy, nhưng tôi sẽ ngạc nhiên nếu nó nhanh hơn headtrong trường hợp này. headVề cơ bản, đó là một lỗi .


2
Trừ khi các dòng có chiều rộng cố định theo byte, bạn không biết nơi để di chuyển con trỏ tệp mà không tính các ký tự dòng mới từ đầu tệp.
Joseph Lust

Điều này không cung cấp một câu trả lời cho câu hỏi. Để phê bình hoặc yêu cầu làm rõ từ một tác giả, hãy để lại nhận xét bên dưới bài đăng của họ.
shoutuma

@exhuma Bạn nói đúng. Tôi viết lại. Bảy năm trước, tôi bị đánh lừa. :)
thư giãn

20

Thế còn:

tail -n +347340107 filename | head -n 100

Tôi đã không kiểm tra nó, nhưng tôi nghĩ rằng nó sẽ làm việc.


Không, thường thì đuôi có giới hạn 256 kilobyte cuối hoặc tương tự, tùy thuộc vào phiên bản và HĐH.
Antti Rytsölä

Mill cối xay yessire
dctremblay

13

Tôi thích chỉ đi vào less

  • 50%để goto nửa tập tin,
  • 43210G đi đến dòng 43210
  • :43210 để làm cái tương tự

và những thứ như thế.

Thậm chí tốt hơn: nhấn vđể bắt đầu chỉnh sửa (tất nhiên là trong vim!), Tại vị trí đó. Bây giờ, lưu ý rằng vimcó các ràng buộc quan trọng tương tự!


12

Trước tiên tôi muốn chia tệp thành nhiều tệp nhỏ hơn như thế này

$ split --lines=50000 /path/to/large/file /path/to/output/file/prefix

và sau đó grep trên các tập tin kết quả.


đồng ý, phá vỡ đăng nhập đó và tạo một công việc định kỳ để làm điều đó đúng. sử dụng logrotate hoặc một cái gì đó tương tự để giữ cho chúng không bị quá lớn.
Tanj

9

Bạn có thể sử dụng exlệnh, trình soạn thảo Unix tiêu chuẩn (một phần của Vim ngay bây giờ), vd

  • hiển thị một dòng duy nhất (ví dụ: dòng thứ 2):

    ex +2p -scq file.txt

    cú pháp sed tương ứng: sed -n '2p' file.txt

  • phạm vi của các dòng (ví dụ: 2-5 dòng):

    ex +2,5p -scq file.txt

    cú pháp sed: sed -n '2,5p' file.txt

  • từ dòng đã cho đến hết (ví dụ thứ 5 đến cuối tập tin):

    ex +5,p -scq file.txt

    cú pháp sed: sed -n '2,$p' file.txt

  • nhiều phạm vi dòng (ví dụ 2-4 và 6-8 dòng):

    ex +2,4p +6,8p -scq file.txt

    cú pháp sed: sed -n '2,4p;6,8p' file.txt

Các lệnh trên có thể được kiểm tra với tệp kiểm tra sau:

seq 1 20 > file.txt

Giải trình:

  • +hoặc -ctheo sau bởi lệnh - thực thi lệnh (vi / vim) sau khi tệp đã được đọc,
  • -s - chế độ im lặng, cũng sử dụng thiết bị đầu cuối hiện tại làm đầu ra mặc định,
  • qtheo sau -clà lệnh thoát trình soạn thảo (thêm !vào để thực hiện thoát lệnh, vd -scq!).

6

Nếu số dòng của bạn là 100 để đọc

head -100 filename | tail -1

6

Được ack

Cài đặt Ubuntu / Debian:

$ sudo apt-get install ack-grep

Sau đó chạy:

$ ack --lines=$START-$END filename

Thí dụ:

$ ack --lines=10-20 filename

Từ $ man ack:

--lines=NUM
    Only print line NUM of each file. Multiple lines can be given with multiple --lines options or as a comma separated list (--lines=3,5,7). --lines=4-7 also works. 
    The lines are always output in ascending order, no matter the order given on the command line.

1
Điều này, với tôi có vẻ giống như lệnh với cú pháp trực quan nhất trong số tất cả các câu trả lời ở đây.
nzn

Từ phiên bản 2.999_06 ngày 10 tháng 1 năm 2019, --linestham số đã bị xóa.
bỏng

4

sed sẽ cần phải đọc dữ liệu quá để đếm các dòng. Cách duy nhất một lối tắt sẽ có thể là có ngữ cảnh / thứ tự trong tệp để hoạt động. Ví dụ: nếu có các dòng nhật ký được đặt trước với thời gian / ngày có chiều rộng cố định, v.v. bạn có thể sử dụng tiện ích look unix để tìm kiếm nhị phân thông qua các tệp cho ngày / lần cụ thể


4

Sử dụng

x=`cat -n <file> | grep <match> | awk '{print $1}'`

Tại đây bạn sẽ nhận được số dòng nơi trận đấu xảy ra.

Bây giờ bạn có thể sử dụng lệnh sau để in 100 dòng

awk -v var="$x" 'NR>=var && NR<=var+100{print}' <file>

hoặc bạn cũng có thể sử dụng "sed"

sed -n "${x},${x+100}p" <file>

Nếu bạn có nhiều trận đấu, hãy sử dụng: "awk 'NR == 1 {print $ 1}" cho trận đấu đầu tiên, v.v.
Ramana Reddy

2

Với sed -e '1,N d; M q'bạn sẽ in các dòng N + 1 đến M. Điều này có lẽ tốt hơn một chút grep -Cvì nó không cố gắng khớp các dòng với một mẫu.


-elà tùy chọn ở đây.
Flow2k

2

Dựa trên câu trả lời của Sklivvz, đây là một chức năng hay mà người ta có thể đặt trong một .bash_aliasestệp. Nó là hiệu quả trên các tập tin lớn khi in các công cụ từ phía trước của tập tin.

function middle()
{
    startidx=$1
    len=$2
    endidx=$(($startidx+$len))
    filename=$3

    awk "FNR>=${startidx} && FNR<=${endidx} { print NR\" \"\$0 }; FNR>${endidx} { print \"END HERE\"; exit }" $filename
}

1

Để hiển thị một dòng từ một <textfile>bởi nó <line#>, chỉ cần làm như sau:

perl -wne 'print if $. == <line#>' <textfile>

Nếu bạn muốn một cách mạnh mẽ hơn để hiển thị một loạt các dòng với các biểu thức chính quy - tôi sẽ không nói tại sao grep là một ý tưởng tồi để làm điều này, nó khá rõ ràng - biểu thức đơn giản này sẽ cho bạn thấy phạm vi của bạn trong một vượt qua một lần duy nhất đó là những gì bạn muốn khi xử lý các tệp văn bản ~ 20GB:

perl -wne 'print if m/<regex1>/ .. m/<regex2>/' <filename>

(mẹo: nếu regex của bạn có /trong đó, hãy sử dụng cái gì đó như m!<regex>!thay thế)

Điều này sẽ in ra <filename>bắt đầu với dòng phù hợp <regex1>cho đến khi (và bao gồm) dòng phù hợp <regex2>.

Nó không cần một trình hướng dẫn để xem làm thế nào một vài điều chỉnh có thể làm cho nó mạnh hơn nữa.

Điều cuối cùng: perl, vì nó là một ngôn ngữ trưởng thành, có nhiều cải tiến ẩn để ưu tiên tốc độ và hiệu suất. Với suy nghĩ này, nó làm cho nó trở thành sự lựa chọn rõ ràng cho một hoạt động như vậy vì nó ban đầu được phát triển để xử lý các tệp nhật ký lớn, văn bản, cơ sở dữ liệu, v.v.


thực sự, nó không giống với tôi, vì khi chạy một lệnh perl phức tạp hơn nói, chạy 2+ chương trình được nối với nhau (tiếp tục xuống trang), và, tôi nghĩ rằng bạn thực sự đang nói vì tôi đã gõ nhiều hơn một lời giải thích yêu cầu bạn ĐỌC, vì có những trang không phức tạp (hoặc hơn) xuống trang không bị thổi ra khỏi nước ... sheesh
osirisgothra

Lưu ý rằng người dùng đã yêu cầu một loạt các dòng - ví dụ của bạn có thể được điều chỉnh một cách tầm thường.
Sklivvz

0

Bạn có thể thử lệnh này:

egrep -n "*" <filename> | egrep "<line number>"

0

Dễ dàng với perl! Nếu bạn muốn nhận 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

1
Bạn nói nó dễ dàng với awk, nhưng thay vào đó bạn đã làm nó trong perl?
Tù nhân 13

0

Tôi ngạc nhiên chỉ có một câu trả lời khác (của Ramana Reddy) đề nghị thêm số dòng vào đầu ra. Các tìm kiếm sau đây cho số dòng yêu cầu và tô màu đầu ra.

file=FILE
lineno=LINENO
wb="107"; bf="30;1"; rb="101"; yb="103"
cat -n ${file} | { GREP_COLORS="se=${wb};${bf}:cx=${wb};${bf}:ms=${rb};${bf}:sl=${yb};${bf}" grep --color -C 10 "^[[:space:]]\\+${lineno}[[:space:]]"; }

Câu trả lời với mã chỉ có xu hướng bị gắn cờ để xóa. Bạn có thể thêm một số bình luận xung quanh làm thế nào điều này giải quyết vấn đề?
Graham
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.