Если я хочу tailтекстовый tailфайл размером 25 ГБ, команда читает весь файл?
Поскольку файл может быть разбросан по диску, я полагаю, что это необходимо, но я плохо разбираюсь в таких внутренностях.
Если я хочу tailтекстовый tailфайл размером 25 ГБ, команда читает весь файл?
Поскольку файл может быть разбросан по диску, я полагаю, что это необходимо, но я плохо разбираюсь в таких внутренностях.
Ответы:
Нет, tailне читает весь файл, он стремится к концу, затем читает блоки назад, пока не будет достигнуто ожидаемое количество строк, затем отображает строки в правильном направлении до конца файла и, возможно, продолжает отслеживать файл, если -fопция используется.
Однако обратите внимание, что у tailнего нет выбора, кроме как прочитать все данные, если они предоставлены без возможности поиска, например, при чтении из канала.
Точно так же, когда его просят искать строки, начинающиеся с начала файла, с использованием tail -n +linenumberсинтаксиса или tail +linenumberнестандартной опции, когда поддерживается, tailочевидно, читает весь файл (если он не прерван).
tail +nбудет прочитан весь файл - сначала найти нужное количество новых строк, затем вывести остальные.
tailреализации делают это или делают это правильно. Например, busybox 1.21.1 не tailработает в этом отношении. Также обратите внимание, что поведение меняется при использовании tailstdin и где stdin является обычным файлом, а начальная позиция в файле не в начале, когда tailвызывается (как в { cat > /dev/null; tail; } < file)
Вы могли видеть, как tailработает сам. Как вы можете, для одного из моих файлов readэто делается три раза, и в общей сложности читается примерно 10 Кбайт:
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 узнает, где на диске найти конец файла?"
Ответ прост: Хвост не знает. Процессы пользовательского уровня рассматривают файлы как непрерывные потоки, поэтому все, что tailможно знать, это смещение от начала файла. Но в файловой системе «inode» файла (запись каталога) связана со списком чисел, обозначающих физическое расположение блоков данных файла. Когда вы читаете из файла, ядро / драйвер устройства выясняет, какая часть вам нужна, определяет ее местоположение на диске и выбирает ее для вас.
Для таких вещей у нас есть операционные системы: вам не нужно беспокоиться о том, где разбросаны блоки вашего файла.
Если headили tail кажется, что он читает весь файл, вероятная причина состоит в том, что файл содержит мало или вообще не содержит символов новой строки . Я споткнулся об этом несколько месяцев назад с очень большим (гигабайтным) BLOB-объектом JSON, который был сериализован без пробелов, даже в виде строк.
Если у вас GNU head / tail, вы можете использовать -c Nдля печати первых / последних N байтов вместо строк , но, к сожалению, это не функция POSIX.
Как вы можете видеть в строке исходного кода 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. */