답변:
아니요, tail
전체 파일을 읽지 않고 끝까지 검색 한 다음 예상 줄 수에 도달 할 때까지 블록을 뒤로 읽은 다음 파일 끝까지 올바른 방향으로 행을 표시하고 -f
옵션이 사용되는 경우 파일 .
그러나 tail
파이프에서 읽을 때와 같이 검색 할 수없는 입력이 제공된 경우 전체 데이터를 읽는 것 외에는 선택의 여지가 없습니다.
마찬가지로, 지원되는 경우 tail -n +linenumber
구문 또는 tail +linenumber
비표준 옵션 을 사용하여 파일 시작 부분부터 시작하여 줄을 찾도록 요청 tail
하면 전체 파일을 읽습니다 (중단되지 않은 경우).
tail +n
전체 파일을 읽습니다. 먼저 원하는 수의 줄 바꿈을 찾은 다음 나머지를 출력합니다.
tail
구현이 제대로 수행 되지는 않습니다 . 예를 들어 busybox 1.21.1 tail
은 이와 관련하여 손상되었습니다. 또한 때 행동이 달라주의 tail
표준 입력을 보내고 및 표준 입력은 일반 파일과 파일의 초기 위치입니다 때 시작 부분에없는 tail
(처럼 호출 { cat > /dev/null; tail; } < file
)
tail
자신이 어떻게 작동 하는지 볼 수 있습니다 . 내 파일 중 하나에 대해 read
세 번 수행되며 총 약 10K 바이트를 읽습니다.
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
strace
tail
실행될 때 시스템 호출이 수행하는 작업을 보여줍니다 . 시스템 호출에 대한 소개는 en.wikipedia.org/wiki/System_call에서 읽을 수 있습니다 . 간단히-열기-파일을 열고 핸들 (이 예에서는 3), lseek
읽을 위치와 읽은 위치를 읽은 후 read
읽은 바이트 수를 반환합니다.
파일이 디스크에 흩어져있을 수 있기 때문에 [파일을 순차적으로 읽어야한다] 고 생각하지만 그러한 내부 구조를 잘 이해하지 못합니다.
아시다시피, tail
파일의 끝 부분 (시스템 호출 lseek
)을 찾고 뒤로 작동합니다. 그러나 위에서 인용 한 말에서 "꼬리가 파일의 끝을 찾기 위해 디스크의 어디에 있는지 어떻게 알 수 있습니까?"
대답은 간단하다 : 꼬리는 모른다. 사용자 수준 프로세스는 파일을 연속 스트림으로 인식하므로 tail
파일 시작의 오프셋을 알 수 있습니다. 그러나 파일 시스템에서 파일의 "inode"(디렉토리 항목)는 파일 데이터 블록의 물리적 위치를 나타내는 숫자 목록과 연관됩니다. 파일을 읽을 때 커널 / 장치 드라이버는 필요한 부분을 파악하고 디스크상의 위치를 파악하여 가져옵니다.
그것은 우리가 운영 체제를 가지고있는 종류입니다. 따라서 파일 블록이 어디에 흩어져 있는지 걱정할 필요가 없습니다.
당신은에서 볼 수 있듯이 소스 코드 라인 (525), 당신은 구현에 대한 설명을 볼 수 있습니다.
/* 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. */