Não se trata de adicionar uma nova linha extra no final de um arquivo, mas de não remover a nova linha que deveria estar lá.
Um arquivo de texto , no unix, consiste em uma série de linhas , cada uma das quais termina com um caractere de nova linha ( \n
). Um arquivo que não está vazio e não termina com uma nova linha não é, portanto, um arquivo de texto.
Os utilitários que devem operar com arquivos de texto podem não funcionar bem com arquivos que não terminam com uma nova linha; utilitários Unix históricos podem ignorar o texto após a última nova linha, por exemplo. Os utilitários GNU têm uma política de comportamento decente com arquivos que não são de texto, assim como a maioria dos outros utilitários modernos, mas você ainda pode encontrar um comportamento estranho com arquivos que não possuem uma nova linha final¹.
Com o GNU diff, se um dos arquivos comparados termina com uma nova linha, mas não com o outro, é preciso observar esse fato. Como o diff é orientado a linhas, não é possível indicar isso armazenando uma nova linha para um dos arquivos, mas não para os outros - as novas linhas são necessárias para indicar onde cada linha no arquivo diff é iniciada e finalizada. O diff usa esse texto especial \ No newline at end of file
para diferenciar um arquivo que não terminou em uma nova linha de um arquivo que terminou.
A propósito, em um contexto C, um arquivo de origem também consiste em uma série de linhas. Mais precisamente, uma unidade de tradução é vista em uma implementação definida como uma série de linhas, cada uma das quais deve terminar com um caractere de nova linha ( n1256 §5.1.1.1). Em sistemas unix, o mapeamento é direto. No DOS e no Windows, cada sequência CR LF ( \r\n
) é mapeada para uma nova linha ( \n
; é o que sempre acontece ao ler um arquivo aberto como texto nesses sistemas operacionais). Existem alguns sistemas operacionais por aí que não têm um caractere de nova linha, mas possuem registros de tamanho fixo ou variável; nesses sistemas, o mapeamento de arquivos para a origem C introduz um\n
no final de cada registro. Embora isso não seja diretamente relevante para o unix, significa que, se você copiar um arquivo de origem C que está perdendo sua nova linha final em um sistema com arquivos de texto com base em registros e copiá-lo novamente, você terminará com o arquivo incompleto a última linha truncada na conversão inicial ou uma nova linha extra pregada nela durante a conversão reversa.
¹
Exemplo: a saída da classificação GNU sempre termina com uma nova linha. Portanto, se o arquivo foo
estiver com sua nova linha final em falta, você encontrará sort foo | wc -c
um relatório a mais de um caractere cat foo | wc -c
.