A cauda lê o arquivo inteiro?

113

Se eu quiser tailum arquivo de texto de 25 GB, o tailcomando lê o arquivo inteiro?

Como um arquivo pode estar espalhado em um disco, imagino que seja necessário, mas não entendo bem esses internos.

The Unfun Cat
fonte

Respostas:

119

Não, tailnão lê o arquivo inteiro, procura até o fim e depois lê blocos para trás até que o número esperado de linhas seja atingido, depois exibe as linhas na direção correta até o final do arquivo e, possivelmente, continua monitorando o arquivo se a -fopção for usada.

Observe, no entanto, que tailnão há escolha a não ser ler todos os dados, se for fornecida uma entrada não procurável, por exemplo, ao ler de um tubo.

Da mesma forma, quando solicitado a procurar linhas a partir do início do arquivo, com o uso da tail -n +linenumbersintaxe ou da tail +linenumberopção não padrão, quando suportado, tailobviamente lê o arquivo inteiro (a menos que seja interrompido).

jlliagre
fonte
14
Droga, rápido demais :-). Aqui está o código fonte relevante . Imprima as últimas linhas N_LINES do final do arquivo FD. Volte pelo arquivo, lendo os bytes 'BUFSIZ' de cada vez (exceto provavelmente o primeiro), até chegarmos ao início do arquivo ou ler NUMBER newlines.
Patrick
1
Além disso, tail +nlerá o arquivo inteiro - primeiro para encontrar o número desejado de novas linhas e depois para o restante.
SF.
@SF. Na verdade, resposta atualizada.
Jlliagre #
4
Observe que nem todas as tailimplementações fazem ou fazem isso corretamente. Por exemplo, o busybox 1.21.1 tailestá quebrado nesse sentido. Observe também que o comportamento varia quando tailing stdin e onde stdin é um arquivo regular e a posição inicial no arquivo não está no início, quando tailé invocado (como em { cat > /dev/null; tail; } < file)
Stéphane Chazelas
4
@StephaneChazelas * nix - o mundo de casos extremos estranhos se tornando normais. (Embora as entradas buscáveis ​​versus as não procuráveis ​​sejam definitivamente um ponto válido.)
um CVn
69

Você poderia ter visto como tailfunciona a si mesmo. Como você pode, um dos meus arquivos readé feito três vezes e, no total, são lidos aproximadamente 10K bytes:

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
Sergei Kurenkov
fonte
Não vejo como isso responde à pergunta. Você pode explicar o que está acontecendo aqui?
Iain Samuel McLean Elder
10
stracemostra o que as chamadas taildo sistema fazem quando são executadas. Algumas apresentações sobre chamadas do sistema, você pode ler aqui en.wikipedia.org/wiki/System_call . Resumidamente - aberta - abre um arquivo e retorna uma alça (3 neste exemplo), lseekposições onde você está indo para ler e readapenas lê e como você pode ver ele retorna quantos bytes são lidos,
Sergei Kurenkov
2
Portanto, analisando as chamadas do sistema, às vezes você pode entender como um programa funciona.
Sergei Kurenkov 29/11
26

Como um arquivo pode estar espalhado em um disco, imagino que ele tenha que [ler o arquivo sequencialmente], mas não entendo bem esses internos.

Como você sabe agora, tailapenas procura o final do arquivo (com a chamada do sistema lseek) e trabalha para trás. Mas na observação citada acima, você está se perguntando "como a cauda sabe onde está o disco para encontrar o final do arquivo?"

A resposta é simples: cauda não sabe. Os processos no nível do usuário veem os arquivos como fluxos contínuos, para que todos tailsaibam o deslocamento desde o início do arquivo. Mas no sistema de arquivos, o "inode" (entrada de diretório) do arquivo está associado a uma lista de números que indicam a localização física dos blocos de dados do arquivo. Quando você lê o arquivo, o kernel / driver de dispositivo descobre qual parte você precisa, calcula sua localização no disco e a busca por você.

Esse é o tipo de coisa para a qual temos sistemas operacionais: assim você não precisa se preocupar com a dispersão dos blocos de arquivos.

alexis
fonte
2

Se headou tail parece estar lendo o arquivo inteiro, um motivo provável é que o arquivo contenha poucos ou nenhum caractere de nova linha . Tropecei nisso há alguns meses com um blob JSON muito grande (gigabytes) que havia sido serializado sem nenhum espaço em branco, nem mesmo em cadeias.

Se você possui GNU head / tail, pode usar -c Npara imprimir o primeiro / último N bytes em vez de linhas , mas infelizmente este não é um recurso POSIX.

zwol
fonte
1

Como você pode ver na linha de código-fonte 525, você pode ver os comentários para a implementação.

 /* 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.  */
Seenivasan
fonte