Presumo que todos aqui estejam familiarizados com o ditado de que todos os arquivos de texto devem terminar com uma nova linha. Eu conheço essa "regra" há anos, mas sempre me perguntei - por quê?
file
unix
text-files
newline
Will Robertson
fonte
fonte
Respostas:
Porque é assim que o padrão POSIX define uma linha :
Portanto, as linhas que não terminam em um caractere de nova linha não são consideradas linhas reais. É por isso que alguns programas têm problemas ao processar a última linha de um arquivo, se não houver uma nova linha finalizada.
Há pelo menos uma grande vantagem nessa diretriz ao trabalhar em um emulador de terminal: Todas as ferramentas Unix esperam essa convenção e trabalham com ela. Por exemplo, ao concatenar arquivos com
cat
, um arquivo encerrado por nova linha terá um efeito diferente de um sem:E, como o exemplo anterior também demonstra, ao exibir o arquivo na linha de comando (por exemplo, via
more
), um arquivo finalizado por nova linha resulta em uma exibição correta. Um arquivo finalizado incorretamente pode estar distorcido (segunda linha).Para maior consistência, é muito útil seguir esta regra - caso contrário, haverá um trabalho extra ao lidar com as ferramentas padrão do Unix.
Pense de maneira diferente: se as linhas não são terminadas por nova linha, tornar os comandos
cat
úteis é muito mais difícil: como você faz um comando para concatenar arquivos comob.txt
ec.txt
?É claro que isso é solucionável, mas você precisa tornar o uso
cat
mais complexo (adicionando argumentos de linha de comando posicionais, por exemplocat a.txt --no-newline b.txt c.txt
), e agora o comando, em vez de cada arquivo individual, controla como é colado junto com outros arquivos. Isso quase certamente não é conveniente.… Ou você precisa introduzir um caractere sentinela especial para marcar uma linha que deve continuar e não terminar. Bem, agora você está preso à mesma situação que no POSIX, exceto invertido (continuação de linha em vez de caractere de término de linha).
Agora, em sistemas não compatíveis com POSIX (hoje em dia principalmente no Windows), o ponto é discutível: os arquivos geralmente não terminam com uma nova linha, e a definição (informal) de uma linha pode, por exemplo, ser "texto que é separado por novas linhas" (observe a ênfase). Isso é totalmente válido. Entretanto, para dados estruturados (por exemplo, código de programação), a análise é minimamente mais complicada: geralmente significa que os analisadores precisam ser reescritos. Se um analisador foi originalmente escrito com a definição POSIX em mente, pode ser mais fácil modificar o fluxo do token do que o analisador - em outras palavras, adicione um token de "nova linha artificial" ao final da entrada.
fonte
cat
de uma maneira que seja útil e consistente.Cada linha deve terminar em um caractere de nova linha, incluindo o último. Alguns programas têm problemas ao processar a última linha de um arquivo, se a nova linha não for finalizada.
O GCC alerta sobre isso não porque não pode processar o arquivo, mas porque precisa fazer parte do padrão.
Referência: o arquivo de mensagens GCC / GNU .
fonte
wc -l
não contará a última linha de um arquivo se ele não for finalizado com a nova linha. Além disso,cat
unirá a última linha de um arquivo com a primeira linha do próximo arquivo em uma, se a última linha do primeiro arquivo não for finalizada com a nova linha. Praticamente qualquer programa que esteja procurando novas linhas como delimitador tem o potencial de atrapalhar isso.wc
se já foi mencionado ....cat
ewc
)?Esta resposta é uma tentativa de uma resposta técnica e não de opinião.
Se queremos ser puristas do POSIX, definimos uma linha como:
Fonte: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_206
Uma linha incompleta como:
Fonte: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_195
Um arquivo de texto como:
Fonte: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_397
Uma sequência como:
Fonte: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_396
Deste então, podemos derivar que a única vez que vamos potencialmente encontrar qualquer tipo de questões são se lidar com o conceito de uma linha de um arquivo ou um arquivo como um arquivo de texto (sendo que um arquivo de texto é uma organização igual a zero ou mais linhas, e uma linha que conhecemos deve terminar com um <newline>).
Caso em questão:
wc -l filename
.No
wc
manual, lemos:Quais são as implicações nos arquivos JavaScript, HTML e CSS, pois são arquivos de texto ?
Em navegadores, IDEs modernos e outros aplicativos front-end, não há problemas em ignorar o EOL no EOF. Os aplicativos analisarão os arquivos corretamente. Como nem todos os sistemas operacionais estão em conformidade com o padrão POSIX, seria impraticável que ferramentas que não sejam de sistema operacional (por exemplo, navegadores) manipulem arquivos de acordo com o padrão POSIX (ou qualquer padrão no nível do sistema operacional).
Como resultado, podemos estar relativamente confiantes de que o EOL no EOF não terá praticamente nenhum impacto negativo no nível do aplicativo - independentemente de estar em execução em um SO UNIX.
Neste ponto, podemos dizer com segurança que ignorar o EOL no EOF é seguro ao lidar com JS, HTML, CSS no lado do cliente. Na verdade, podemos afirmar que minimizar qualquer um desses arquivos, que não contenha <newline>, é seguro.
Podemos dar um passo adiante e dizer que, no que diz respeito ao NodeJS, ele também não pode aderir ao padrão POSIX, pois pode ser executado em ambientes não compatíveis com POSIX.
O que nos resta então? Ferramentas no nível do sistema.
Isso significa que os únicos problemas que podem surgir são as ferramentas que se esforçam para aderir sua funcionalidade à semântica do POSIX (por exemplo, definição de uma linha conforme mostrado em
wc
).Mesmo assim, nem todas as conchas aderem automaticamente ao POSIX. O Bash, por exemplo, não é padrão para o comportamento POSIX. Há um interruptor para ativá-lo:
POSIXLY_CORRECT
.Alimento para reflexão sobre o valor da EOL <newline>: https://www.rfc-editor.org/old/EOLstory.txt
Permanecendo na trilha de ferramentas, para todos os propósitos e propósitos práticos, vamos considerar o seguinte:
Vamos trabalhar com um arquivo que não possui EOL. No momento da redação deste documento, o arquivo neste exemplo é um JavaScript minificado sem EOL.
Observe que o
cat
tamanho do arquivo é exatamente a soma de suas partes individuais. Se a concatenação de arquivos JavaScript for uma preocupação para arquivos JS, a preocupação mais apropriada seria iniciar cada arquivo JavaScript com ponto e vírgula.Como outra pessoa mencionada neste tópico: e se você quiser
cat
dois arquivos cuja saída se torne apenas uma linha em vez de duas? Em outras palavras,cat
faz o que deveria fazer.O
man
decat
apenas menciona a entrada de leitura até EOF, não <newline>. Observe que a-n
opção decat
imprimir também imprimirá uma linha não terminada não <nova linha> (ou linha incompleta ) como uma linha - sendo que a contagem começa em 1 (de acordo com oman
.)Agora que entendemos como o POSIX define uma linha , esse comportamento se torna ambíguo ou realmente não compatível.
A compreensão do objetivo e da conformidade de uma determinada ferramenta ajudará a determinar o quão crítico é finalizar os arquivos com uma EOL. Em C, C ++, Java (JARs), etc ... alguns padrões determinam uma nova linha de validade - esse padrão não existe para JS, HTML, CSS.
Por exemplo, em vez de usar o que
wc -l filename
se poderia fazerawk '{x++}END{ print x}' filename
, tenha certeza de que o sucesso da tarefa não será prejudicado por um arquivo que poderemos processar que não escrevemos (por exemplo, uma biblioteca de terceiros como a JS minificada que damoscurl
) - a menos que nosso A intenção era realmente contar linhas no sentido compatível com POSIX.Conclusão
Haverá muito poucos casos de uso da vida real em que ignorar o EOL no EOF para determinados arquivos de texto, como JS, HTML e CSS, terá um impacto negativo - se houver. Se confiarmos na presença de <newline>, restringiremos a confiabilidade de nossas ferramentas apenas aos arquivos que criamos e nos abrimos para possíveis erros introduzidos por arquivos de terceiros.
Moral da história: ferramentas de engenheiro que não têm a fraqueza de confiar na EOL na EOF.
Sinta-se à vontade para postar casos de uso, como eles se aplicam a JS, HTML e CSS, onde podemos examinar como ignorar o EOL tem um efeito adverso.
fonte
Pode estar relacionado à diferença entre :
Se cada linha termina em um final de linha, isso evita, por exemplo, que a concatenação de dois arquivos de texto faça com que a última linha da primeira seja executada na primeira linha da segunda.
Além disso, um editor pode verificar se o arquivo termina em um final de linha, salva-o na opção local 'eol' e o usa ao gravar o arquivo.
Alguns anos atrás (2005), muitos editores (ZDE, Eclipse, Scite, ...) "esqueceram" a EOL final, o que não foi muito apreciado .
Não apenas isso, mas eles interpretaram a EOL final incorretamente, como 'iniciar uma nova linha' e, na verdade, começam a exibir outra linha como se ela já existisse.
Isso ficou muito visível com um arquivo de texto 'adequado' com um editor de texto bem-comportado como o vim, comparado a abri-lo em um dos editores acima. Ele exibia uma linha extra abaixo da última linha real do arquivo. Você vê algo assim:
fonte
Algumas ferramentas esperam isso. Por exemplo,
wc
espera isso:fonte
wc
não espera isso, por mais que esteja simplesmente trabalhando dentro da definição POSIX de "linha" em oposição à compreensão intuitiva da maioria das pessoas sobre "linha".wc -l
imprimir1
nos dois casos, mas algumas pessoas podem dizer que o segundo caso deve ser impresso2
.\n
em um terminador de linha, e não como um separador de linha, como o POSIX / UNIX, então esperar que o segundo caso imprima 2 é absolutamente louco.Basicamente, existem muitos programas que não processam os arquivos corretamente se eles não obtiverem o EOL EOF final.
O GCC alerta sobre isso porque é esperado como parte do padrão C. (seção 5.1.1.2 aparentemente)
Aviso do compilador "Nenhuma nova linha no final do arquivo"
fonte
Isso se origina desde os primeiros dias em que terminais simples foram usados. O novo caractere de linha foi usado para disparar uma 'descarga' dos dados transferidos.
Hoje, o novo caractere de linha não é mais necessário. Claro, muitos aplicativos ainda têm problemas se a nova linha não estiver lá, mas consideraria um bug nesses aplicativos.
Se, no entanto, você possui um formato de arquivo de texto em que precisa da nova linha, você obtém uma verificação simples de dados muito barata: se o arquivo termina com uma linha que não tem nova linha no final, você sabe que o arquivo está quebrado. Com apenas um byte extra para cada linha, você pode detectar arquivos quebrados com alta precisão e quase sem tempo de CPU.
fonte
Um caso de uso separado: quando seu arquivo de texto é controlado por versão (neste caso, especificamente no git, embora também se aplique a outros). Se o conteúdo for adicionado ao final do arquivo, a linha que era anteriormente a última linha será editada para incluir um caractere de nova linha. Isso significa que
blame
o arquivo para descobrir quando a última linha foi editada mostrará a adição de texto, não a confirmação antes que você realmente queria ver.fonte
\n
). Problema resolvido.Além das razões práticas acima, não me surpreenderia se os criadores do Unix (Thompson, Ritchie, et al.) Ou seus antecessores Multics perceberam que há uma razão teórica para usar terminadores de linha em vez de separadores de linha: Com linha terminadores, você pode codificar todos os arquivos de linhas possíveis. Com os separadores de linha, não há diferença entre um arquivo com zero linhas e um arquivo contendo uma única linha vazia; ambos são codificados como um arquivo que contém zero caracteres.
Então, os motivos são:
wc -l
não contará uma "linha" final se não terminar com uma nova linha.cat
apenas funciona e funciona sem complicações. Ele apenas copia os bytes de cada arquivo, sem necessidade de interpretação. Eu não acho que exista um DOS equivalentecat
. O usocopy a+b c
acabará mesclando a última linha do arquivoa
com a primeira linha do arquivob
.fonte
Eu me pergunto isso há anos. Mas me deparei com uma boa razão hoje.
Imagine um arquivo com um registro em todas as linhas (por exemplo, um arquivo CSV). E que o computador estava gravando registros no final do arquivo. Mas de repente caiu. Gee foi a última linha completa? (não é uma situação agradável)
Mas se sempre terminamos a última linha, saberíamos (basta verificar se a última linha está terminada). Caso contrário, provavelmente teríamos que descartar a última linha todas as vezes, apenas para estarmos seguros.
fonte
Presumivelmente, simplesmente que algum código de análise esperava que ele estivesse lá.
Não tenho certeza se consideraria uma "regra", e certamente não é algo que eu adira religiosamente. O código mais sensato saberá analisar o texto (incluindo codificações) linha por linha (qualquer opção de final de linha), com ou sem uma nova linha na última linha.
De fato - se você terminar com uma nova linha: existe (em teoria) uma linha final vazia entre a EOL e a EOF? Um para refletir ...
fonte
Há também um problema prático de programação com arquivos sem novas linhas no final: o
read
Bash interno (não sei sobre outrasread
implementações) não funciona como o esperado:Isso imprime apenas
foo
! O motivo é que, quandoread
encontra a última linha, ele grava o conteúdo,$line
mas retorna o código de saída 1 porque atingiu o EOF. Isso interrompe owhile
ciclo, por isso nunca alcançamos aecho $line
parte. Se você quiser lidar com essa situação, faça o seguinte:Ou seja, faça o
echo
seread
falhou devido a uma linha não vazia no final do arquivo. Naturalmente, nesse caso, haverá uma nova linha extra na saída que não estava na entrada.fonte
Bem expresso por muitos, porque:
Muitos programas não se comportam bem ou falham sem ele.
Mesmo os programas que lidam bem com um arquivo não têm final
'\n'
, a funcionalidade da ferramenta pode não atender às expectativas do usuário - o que pode não ser claro neste caso de canto.Programas raramente desaprovam final
'\n'
(não conheço nenhum).No entanto, isso gera a próxima pergunta:
Mais importante - não escreva código que pressupõe que um arquivo de texto termine com uma nova linha . Assumir que um arquivo esteja em conformidade com um formato leva a corrupção de dados, ataques de hackers e falhas. Exemplo:
Se o rastreamento final
'\n'
for necessário, alerte o usuário sobre sua ausência e as medidas tomadas. IOWs, valide o formato do arquivo. Nota: Isso pode incluir um limite para o comprimento máximo da linha, codificação de caracteres etc.Defina claramente, documento, a manipulação do código de uma final ausente
'\n'
.Não gere , como possível, um arquivo que não possui final
'\n'
.fonte
É muito tarde aqui, mas eu apenas enfrentei um erro no processamento de arquivos e isso ocorreu porque os arquivos não estavam terminando com uma nova linha vazia. Estávamos processando arquivos de texto com
sed
esed
omitindo a última linha da saída, causando a estrutura json inválida e enviando o restante do processo para o estado de falha.Tudo o que estávamos fazendo era:
Há um exemplo de arquivo:
foo.txt
com algumjson
conteúdo dentro dele.O arquivo foi criado na máquina de viúvas e os scripts da janela estavam processando esse arquivo usando os comandos do PowerShell. Tudo bom.
Quando processamos o mesmo arquivo usando o
sed
comandosed 's|value|newValue|g' foo.txt > foo.txt.tmp
O arquivo recém-gerado foi
e boom, falhou no restante dos processos devido ao JSON inválido.
Portanto, é sempre uma boa prática finalizar seu arquivo com uma nova linha vazia.
fonte
Eu sempre tive a impressão de que a regra vinha dos dias em que era difícil analisar um arquivo sem uma nova linha final. Ou seja, você acabaria escrevendo código onde um final de linha foi definido pelo caractere EOL ou EOF. Era mais simples supor que uma linha terminasse com EOL.
No entanto, acredito que a regra é derivada de compiladores C que exigem a nova linha. E, como apontado no aviso do compilador "Nenhuma nova linha no final do arquivo" , #include não adicionará uma nova linha.
fonte
Imagine que o arquivo está sendo processado enquanto o arquivo ainda está sendo gerado por outro processo.
Pode ter a ver com isso? Um sinalizador que indica que o arquivo está pronto para ser processado.
fonte
Pessoalmente, gosto de novas linhas no final dos arquivos de código-fonte.
Pode ter sua origem no Linux ou em todos os sistemas UNIX. Lembro-me de que havia erros de compilação (gcc, se não me engano) porque os arquivos de código-fonte não terminaram com uma nova linha vazia. Por que foi feito dessa maneira, resta-se pensar.
fonte
IMHO, é uma questão de estilo pessoal e opinião.
Antigamente, eu não colocava essa nova linha. Um caractere salvo significa mais velocidade nesse modem de 14,4K.
Posteriormente, coloquei essa nova linha para facilitar a seleção da linha final usando shift + downarrow.
fonte