Por que os arquivos de texto devem terminar com uma nova linha?

1470

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ê?

Will Robertson
fonte
30
apenas um nitpick. não é uma "nova linha" no final do arquivo. É uma "quebra de linha" no final da última linha. Além disso, consulte a melhor resposta em uma pergunta relacionada: stackoverflow.com/questions/16222530/…
gcb
346
Só para escolher um pouco mais, ele não escreveu “nova linha”, ele escreveu “nova linha”, o que está correto.
Sindrenm
5
não familiar, mas pensando que eu sou de fato porque o número de casos em que a nova linha supérfluo é realmente coisas quebrando é um pouco alto demais para o meu gosto
tobibeer
2
Atualmente, estou usando fluxos Node.js para analisar dados de texto sem formatação linha por linha, e a falta de quebra de linha do terminal é irritante, pois preciso adicionar lógica extra para quando o lado de entrada do fluxo for concluído / fechado para garantir que a última linha seja processada.
Mark K Cowan
23
A maneira como o Unix considera seu comportamento geral no final dos arquivos é a seguinte: \ n caracteres não iniciam linhas; em vez disso, eles os terminam. Portanto, \ n é um terminador de linha, não um separador de linha. A primeira linha (como todas as linhas) não precisa \ n para iniciá-la. A última linha (como todas as linhas) precisa de um \ n para finalizá-la. Um \ n no final do arquivo não cria uma linha adicional. Às vezes, no entanto, os editores de texto adicionam uma linha em branco visível. Até o emacs faz isso, opcionalmente .
precisa saber é o seguinte

Respostas:

1383

Porque é assim que o padrão POSIX define uma linha :

3.206 Linha
Uma sequência de zero ou mais caracteres não <newline> mais um caractere <newline> final.

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:

$ more a.txt
foo
$ more b.txt
bar$ more c.txt
baz
$ cat {a,b,c}.txt
foo
barbaz

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 como

  1. coloca o início de cada arquivo em uma nova linha, que é o que você deseja 95% do tempo; mas
  2. permite mesclar a última e a primeira linha de dois arquivos, como no exemplo acima, entre b.txte c.txt?

É claro que isso é solucionável, mas você precisa tornar o uso catmais complexo (adicionando argumentos de linha de comando posicionais, por exemplo cat 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.

Konrad Rudolph
fonte
9
Embora agora seja pouco prático de corrigir, o POSIX cometeu claramente um erro ao definir a linha - como evidência pelo número de perguntas sobre esse assunto. Uma linha deve ter sido definida como zero ou mais caracteres terminados por <eol>, <eof> ou <eol> <eof>. A complexidade do analisador não é uma preocupação válida. Sempre que possível, a complexidade deve ser movida da cabeça dos programadores para a biblioteca.
Doug Coburn
23
@DougCoburn Esta resposta costumava ter uma discussão técnica exaustiva explicando por que isso está errado e por que o POSIX fez a coisa certa. Infelizmente, esses comentários foram aparentemente excluídos recentemente por um moderador excessivamente zeloso. Resumidamente, não se trata de analisar a complexidade; em vez disso, sua definição torna muito mais difícil criar ferramentas, como catde uma maneira que seja útil e consistente.
Konrad Rudolph
8
@ Leon A regra POSIX tem como objetivo reduzir casos extremos. E faz isso muito bem. Na verdade, estou um pouco perplexo com o fato de as pessoas não entenderem isso: é a definição mais simples possível e consistente de uma linha.
Konrad Rudolph
6
@ BT Acho que você está assumindo que meu exemplo de fluxo de trabalho mais conveniente é a razão por trás da decisão. Não é, é apenas uma consequência. O motivo é que a regra POSIX é a regra mais simples e que facilita a manipulação de linhas em um analisador. A única razão pela qual estamos discutindo é que o Windows faz de maneira diferente e, como conseqüência, existem inúmeras ferramentas que falham nos arquivos POSIX. Se todo mundo fizesse POSIX, não haveria nenhum problema. No entanto, as pessoas reclamam do POSIX, não do Windows.
Konrad Rudolph
7
@ BT: Estou apenas me referindo ao Windows para apontar os casos em que as regras POSIX não fazem sentido (em outras palavras, eu estava jogando um osso). Estou mais do que feliz em nunca mais mencioná-lo nesta discussão. Mas sua afirmação faz ainda menos sentido: nas plataformas POSIX, simplesmente não faz sentido discutir arquivos de texto com diferentes convenções de final de linha, porque não há razão para produzi-los. Qual a vantagem? Não há literalmente nenhum. - Em resumo, eu realmente não entendo o ódio que esta resposta (ou a regra POSIX) está gerando. Para ser franco, é completamente irracional.
21319 Konrad Rudolph
282

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.

O padrão da linguagem C diz que um arquivo de origem que não está vazio deve terminar com um caractere de nova linha, que não deve ser imediatamente precedido por um caractere de barra invertida.

Como esta é uma cláusula "deve", devemos emitir uma mensagem de diagnóstico por violação desta regra.

Isso está na seção 2.1.1.2 da norma ANSI C 1989. Seção 5.1.1.2 da norma ISO C 1999 (e provavelmente também a norma ISO C 1990).

Referência: o arquivo de mensagens GCC / GNU .

Bill the Lizard
fonte
17
por favor programas escrever bons, então, que quer permitir que inserir essa nova linha quando necessário durante o processamento ou são capazes de tratar adequadamente "faltando" queridos ... que são, na verdade, não faltando
tobibeer
4
@ BilltheLizard, Quais são alguns exemplos de "Alguns programas têm problemas ao processar a última linha de um arquivo, se a nova linha não for finalizada" ?
Pacerier
4
O @Pacerier wc -lnão contará a última linha de um arquivo se ele não for finalizado com a nova linha. Além disso, catunirá 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.
Bill the Lizard
2
@BilltheLizard, quero dizer wcse já foi mencionado ....
Pacerier
2
@ BilltheLizard, meu mal, para esclarecer: quais são alguns exemplos de programas que apresentam problemas ao processar a última linha de um arquivo se ele não for finalizado com nova linha (além daqueles que já foram mencionados em massa no thread, como cate wc)?
Pacerier 04/07/2015
116

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:

Uma sequência de zero ou mais caracteres não <newline> mais um caractere <newline> final.

Fonte: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_206

Uma linha incompleta como:

Uma sequência de um ou mais caracteres não <newline> no final do arquivo.

Fonte: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_195

Um arquivo de texto como:

Um arquivo que contém caracteres organizados em zero ou mais linhas. As linhas não contêm caracteres NUL e nenhuma pode exceder {LINE_MAX} bytes de comprimento, incluindo o caractere <newline>. Embora o POSIX.1-2008 não faça distinção entre arquivos de texto e arquivos binários (consulte o padrão ISO C), muitos utilitários produzem apenas resultados previsíveis ou significativos ao operar em arquivos de texto. Os utilitários padrão que possuem essas restrições sempre especificam "arquivos de texto" nas seções STDIN ou INPUT FILES.

Fonte: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_397

Uma sequência como:

Uma sequência contígua de bytes terminada por e incluindo o primeiro byte nulo.

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 wcmanual, lemos:

Uma linha é definida como uma sequência de caracteres delimitada por um caractere <newline>.

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.

curl http://cdnjs.cloudflare.com/ajax/libs/AniJS/0.5.0/anijs-min.js -o x.js
curl http://cdnjs.cloudflare.com/ajax/libs/AniJS/0.5.0/anijs-min.js -o y.js

$ cat x.js y.js > z.js

-rw-r--r--  1 milanadamovsky   7905 Aug 14 23:17 x.js
-rw-r--r--  1 milanadamovsky   7905 Aug 14 23:17 y.js
-rw-r--r--  1 milanadamovsky  15810 Aug 14 23:18 z.js

Observe que o cattamanho 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 catdois arquivos cuja saída se torne apenas uma linha em vez de duas? Em outras palavras, catfaz o que deveria fazer.

O mande catapenas menciona a entrada de leitura até EOF, não <newline>. Observe que a -nopção de catimprimir 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 o man.)

-n Numere as linhas de saída, começando em 1.

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 filenamese poderia fazer awk '{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 damos curl) - 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.

Milan Adamovsky
fonte
2
O POSIX não está marcado na pergunta ... o que há sobre as terminações de linha MVS / OS? ou terminações de linha do MS-DOS? A propósito, todos os sistemas posix conhecidos permitem que arquivos de texto sem um final de linha final (nenhum caso encontrado de um sistema de reivindicações compatível com posix no qual "arquivo de texto" tenha tratamento especial no kernel para inserir uma nova linha adequada, caso não exista). -lo)
Luis Colorado
62

Pode estar relacionado à diferença entre :

  • arquivo de texto (cada linha deve terminar em um final de linha)
  • arquivo binário (não existem "linhas" verdadeiras e o tamanho do arquivo deve ser preservado)

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:

1 first line
2 middle line
3 last line
4
VonC
fonte
11
+1. Eu encontrei essa pergunta SO enquanto enfrentava esse mesmo problema. É muito irritante para o Eclipse mostrar essa última linha "falsa" e, se eu removê-la, o git (e todas as outras ferramentas unix que esperam EOL) reclama. Além disso, observe que isso não é apenas em 2005: o Eclipse 4.2 Juno ainda tem esse problema.
MestreLion 28/08/13
@MestreLion, Continuação em stackoverflow.com/questions/729692/…
Pacerier
46

Algumas ferramentas esperam isso. Por exemplo, wcespera isso:

$ echo -n "Line not ending in a new line" | wc -l
0
$ echo "Line ending with a new line" | wc -l
1
Flimm
fonte
22
Eu não diria "alguns", digo que a maioria das ferramentas espera isso para arquivos de texto, se não todos. gato, git, diff, wc, grep, sed ... a lista é enorme
MestreLion
Talvez alguém possa dizer que wcnã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".
Guildenstern
@Guildenstern A definição intuitiva seria para wc -limprimir 1nos dois casos, mas algumas pessoas podem dizer que o segundo caso deve ser impresso 2.
Flimm
@Limlim Se você pensa \nem 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.
ponto
21

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"

cgp
fonte
5
O GCC não é incapaz de processar o arquivo, ele deve emitir o aviso como parte do padrão C.
Bill o lagarto #
O IIRC, MSVC 2005 reclamou dos arquivos C que terminavam com linhas incompletas e possivelmente se recusavam a compilá-los.
Mark K Cowan
16

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.

Stefan
fonte
15
Atualmente, a nova linha no EOF para arquivos de texto pode não ser um requisito, mas é uma convenção útil que faz com que a maioria das ferramentas unix trabalhe em conjunto com resultados consistentes. Não é um bug.
MestreLion 28/08/13
14
Muitos de nós não usamos as ferramentas Unix, e não nos importamos.
precisa saber é o seguinte
12
Não são apenas ferramentas unix, qualquer ferramenta funcionará melhor e / ou será codificada de maneira mais simples se puder assumir formatos de arquivo sensíveis.
Sam Watkins
2
@Sam Watkins Concorda que ter formatos simples e bem definidos é bom. No entanto, o código ainda precisa verificar e não assumir que os dados são compatíveis com o formato.
chux - Restabelece Monica
8
@MestreLion Esse é um legado inútil de um conjunto de ferramentas ruins compatíveis com padrões estúpidos. Esses artefatos da programação extremista (isto é, o arquivo de tudo! Tudo deveria falar em texto simples!) Não morreram logo após sua invenção, porque eram as únicas ferramentas disponíveis desse tipo em um determinado momento da história. C foi substituído pelo C ++, não faz parte do POSIX, não requer EOL no EOF e seu uso (obviamente) é desencorajado por luddists * nix.
polkovnikov.ph
14

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 blameo 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.

Robin Whittleton
fonte
1
diff e culpa devem ser atualizados apenas para detectar "novas linhas" em vez de "novas linhas" ( \n). Problema resolvido.
22419 Andrew Andrew
1
Você pode usar a tag -w para ignorar as alterações de espaço em branco, mas elas não são o padrão.
Robin Whittleton 10/07/19
11

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:

  1. Porque é assim que o POSIX o define.
  2. Porque algumas ferramentas esperam ou "se comportam mal" sem ele. Por exemplo, wc -lnão contará uma "linha" final se não terminar com uma nova linha.
  3. Porque é simples e conveniente. No Unix, catapenas 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 equivalente cat. O uso copy a+b cacabará mesclando a última linha do arquivo acom a primeira linha do arquivo b.
  4. Como um arquivo (ou fluxo) de zero linhas pode ser diferenciado de um arquivo de uma linha vazia.
jrw32982 suporta Monica
fonte
11

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.

simbionte
fonte
10

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 ...

Marc Gravell
fonte
12
Não é uma regra, é uma convenção: uma linha é algo que termina com um final de linha . Portanto, não, não há "linha final vazia" entre EOL e EOF.
MestreLion 28/08
4
@MestreLion: Mas o personagem em questão não é chamado de "fim de linha", é chamado de "nova linha" e / ou "avanço de linha". Um separador de linha, não um terminador de linha. E o resultado é uma linha final vazia.
Ben Voigt
2
Nenhuma ferramenta (sã) contaria o último EOL (CR, LF, etc) de um arquivo como uma linha vazia adicional. E todas as ferramentas POSIX não contarão os últimos caracteres de um arquivo como uma linha se não houver EOL final. Independentemente do nome do caractere EOL ser "avanço de linha" ou "retorno de carro" (não há caractere chamado "nova linha"), para todos os fins práticos, as ferramentas sensíveis o tratam como um terminador de linha , não como um separador de linha .
usar o seguinte comando
2
@MestreLion, você tem certeza de que "terminador de linha" é sensato? Pegue alguns não programadores e faça uma pesquisa rápida. Você perceberá rapidamente que o conceito de linhas está mais próximo do conceito de "separadores de linhas". O conceito de "terminador de linha" é simplesmente estranho .
Pacerier
4
@ Shauagin: Esta não é a minha opinião, é assim que o Padrão POSIX define uma linha. Um arquivo vazio com 0 bytes tem 0 linhas, portanto, nenhuma EOL, e um ficheiro para ser considerado como tendo apenas uma única linha, em branco, que faz requerem um EOL. Observe também que isso é relevante apenas se você quiser contar as linhas em um arquivo, pois obviamente qualquer editor permitirá que você "chegue" à próxima (ou primeira) linha, independentemente de já existir uma EOL.
MestreLion
10

Há também um problema prático de programação com arquivos sem novas linhas no final: o readBash interno (não sei sobre outras readimplementações) não funciona como o esperado:

printf $'foo\nbar' | while read line
do
    echo $line
done

Isso imprime apenasfoo ! O motivo é que, quando readencontra a última linha, ele grava o conteúdo, $linemas retorna o código de saída 1 porque atingiu o EOF. Isso interrompe o whileciclo, por isso nunca alcançamos a echo $lineparte. Se você quiser lidar com essa situação, faça o seguinte:

while read line || [ -n "${line-}" ]
do
    echo $line
done < <(printf $'foo\nbar')

Ou seja, faça o echose readfalhou 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.

l0b0
fonte
9

Por que os arquivos (texto) devem terminar com uma nova linha?

Bem expresso por muitos, porque:

  1. Muitos programas não se comportam bem ou falham sem ele.

  2. 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.

  3. Programas raramente desaprovam final '\n'(não conheço nenhum).


No entanto, isso gera a próxima pergunta:

O que o código deve fazer sobre arquivos de texto sem uma nova linha?

  1. 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:

    // Bad code
    while (fgets(buf, sizeof buf, instream)) {
      // What happens if there is no \n, buf[] is truncated leading to who knows what
      buf[strlen(buf) - 1] = '\0';  // attempt to rid trailing \n
      ...
    }
    
  2. 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.

  3. Defina claramente, documento, a manipulação do código de uma final ausente '\n'.

  4. Não gere , como possível, um arquivo que não possui final '\n'.

chux - Restabelecer Monica
fonte
4

É 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 sedesed 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.txtcom algum jsonconteúdo dentro dele.

[{
    someProp: value
},
{
    someProp: value
}] <-- No newline here

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 sedcomandosed 's|value|newValue|g' foo.txt > foo.txt.tmp

O arquivo recém-gerado foi

[{
    someProp: value
},
{
    someProp: value

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.

Arpit
fonte
3

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.

he_the_great
fonte
0

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.

Pippen_001
fonte
-4

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.

Do utilizador
fonte
-6

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.

Torben Gundtofte-Bruun
fonte