Có đuôi đọc toàn bộ tập tin?


113

Nếu tôi muốn tailmột tailtệp văn bản 25 GB, lệnh có đọc toàn bộ tệp không?

Vì một tập tin có thể nằm rải rác trên đĩa, tôi tưởng tượng nó phải như vậy, nhưng tôi không hiểu rõ về nội bộ như vậy.

Câu trả lời:


119

Không, tailkhông đọc toàn bộ tệp, nó tìm đến cuối rồi đọc ngược khối cho đến khi đạt được số dòng dự kiến, sau đó nó hiển thị các dòng theo hướng thích hợp cho đến khi kết thúc tệp và có thể vẫn theo dõi tập tin nếu -ftùy chọn được sử dụng.

Tuy nhiên, lưu ý rằng tailkhông có lựa chọn nào khác ngoài việc đọc toàn bộ dữ liệu nếu được cung cấp đầu vào không thể tìm kiếm, ví dụ như khi đọc từ một đường ống.

Tương tự, khi được yêu cầu tìm kiếm các dòng bắt đầu từ đầu tệp, với việc sử dụng tail -n +linenumbercú pháp hoặc tail +linenumbertùy chọn không chuẩn khi được hỗ trợ, tailrõ ràng sẽ đọc toàn bộ tệp (trừ khi bị gián đoạn).


14
Chết tiệt, quá nhanh :-). Đây là mã nguồn có liên quan . In các dòng N_LINES cuối cùng từ cuối tệp FD. Đi ngược qua tệp, đọc các byte 'BUFSIZ' tại một thời điểm (ngoại trừ lần đầu tiên), cho đến khi chúng tôi nhấn vào đầu tệp hoặc đã đọc SỐ dòng mới.
Patrick

1
Ngoài ra, tail +nsẽ đọc toàn bộ tệp - đầu tiên để tìm số dòng mới mong muốn, sau đó xuất ra phần còn lại.
SF.

@SF. Thật vậy, câu trả lời cập nhật.
jlliagre

4
Lưu ý rằng không phải tất cả các tailthực hiện làm điều đó hoặc làm điều đó đúng. Ví dụ, busybox 1.21.1 tailbị hỏng trong vấn đề đó. Cũng lưu ý rằng hành vi thay đổi khi tailing stdin và trong đó stdin là tệp thông thường và vị trí ban đầu trong tệp không ở đầu khi tailđược gọi (như trong { cat > /dev/null; tail; } < file)
Stéphane Chazelas

4
@StephaneChazelas * nix - thế giới của những trường hợp kỳ lạ trở nên bình thường. (Mặc dù đầu vào có thể tìm kiếm và không thể tìm kiếm chắc chắn là một điểm hợp lệ.)
CVn

69

Bạn có thể thấy cách làm tailviệc của mình. Như bạn có thể cho một trong các tệp của tôi readđược thực hiện ba lần và tổng cộng khoảng 10K byte được đọc:

strace 2>&1  tail ./huge-file >/dev/null  | grep -e "read" -e "lseek" -e "open" -e "close"
open("./huge-file", O_RDONLY)           = 3
lseek(3, 0, SEEK_CUR)                   = 0
lseek(3, 0, SEEK_END)                   = 80552644
lseek(3, 80551936, SEEK_SET)            = 80551936
read(3, ""..., 708) = 708
lseek(3, 80543744, SEEK_SET)            = 80543744
read(3, ""..., 8192) = 8192
read(3, ""..., 708) = 708
close(3)                                = 0

Tôi không thấy cách này trả lời câu hỏi. Bạn có thể giải thích những gì đang xảy ra ở đây?
Iain Samuel McLean Elder

10
stracehiển thị những gì hệ thống gọi taillàm khi chạy. Một số giới thiệu về các cuộc gọi hệ thống mà bạn có thể đọc ở đây en.wikipedia.org/wiki/System_call . Ngắn gọn - mở - mở một tệp và trả về một tay cầm (3 trong ví dụ này), lseekcác vị trí bạn sẽ đọc và readchỉ đọc và như bạn có thể thấy nó trả về số lượng byte được đọc,
Sergei Kurenkov

2
Vì vậy, phân tích các cuộc gọi hệ thống đôi khi bạn có thể hiểu làm thế nào một chương trình hoạt động.
Sergei Kurenkov

26

Vì một tệp có thể nằm rải rác trên đĩa, tôi tưởng tượng nó phải [đọc tệp liên tục], nhưng tôi không hiểu rõ nội bộ như vậy.

Như bạn đã biết, tailchỉ cần tìm đến cuối tệp (với lệnh gọi hệ thống lseek) và làm việc ngược lại. Nhưng trong phần nhận xét được trích dẫn ở trên, bạn đang tự hỏi "làm thế nào để đuôi biết nơi nào trên đĩa để tìm phần cuối của tệp?"

Câu trả lời rất đơn giản: Đuôi không biết. Các quy trình ở cấp độ người dùng xem các tệp dưới dạng luồng liên tục, vì vậy tất cả tailcó thể biết là phần bù từ đầu tệp. Nhưng trong hệ thống tệp, "inode" của tệp (mục nhập thư mục) được liên kết với một danh sách các số biểu thị vị trí thực của các khối dữ liệu của tệp. Khi bạn đọc từ tệp, kernel / trình điều khiển thiết bị sẽ tìm ra phần bạn cần, tìm ra vị trí của nó trên đĩa và tìm nạp nó cho bạn.

Đó là loại điều chúng tôi có hệ điều hành: vì vậy bạn không phải lo lắng về việc các khối tệp của bạn nằm rải rác ở đâu.


2

Nếu headhoặc tail dường như đang đọc toàn bộ tệp, một lý do có thể là tệp chứa ít hoặc không có ký tự dòng mới . Tôi đã vấp phải điều này một vài tháng trước với một blob JSON (gigabyte) rất lớn đã được tuần tự hóa mà không có khoảng trắng nào, thậm chí không có trong chuỗi.

Nếu bạn có đầu / đuôi GNU, bạn có thể sử dụng -c Nđể in N byte đầu tiên / cuối cùng thay vì các dòng , nhưng thật không may, đây không phải là một tính năng POSIX.


1

Như bạn có thể thấy trong dòng mã nguồn 525, bạn có thể thấy các ý kiến ​​cho việc thực hiện.

 /* Print the last N_LINES lines from the end of file FD.
   Go backward through the file, reading 'BUFSIZ' bytes at a time (except
   probably the first), until we hit the start of the file or have
   read NUMBER newlines.
   START_POS is the starting position of the read pointer for the file
   associated with FD (may be nonzero).
   END_POS is the file offset of EOF (one larger than offset of last byte).
   Return true if successful.  */
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.