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.
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.
Respostas:
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).
tail +nlerá o arquivo inteiro - primeiro para encontrar o número desejado de novas linhas e depois para o restante.
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)
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
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,
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.
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.
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. */