Perché i file di testo dovrebbero terminare con una nuova riga?


1470

Presumo che tutti qui abbiano familiarità con il detto che tutti i file di testo dovrebbero finire con una nuova riga. Conosco questa "regola" da anni ma mi sono sempre chiesto: perché?


30
solo un pazzo. non è una "nuova linea" alla fine del file. È una "interruzione di riga" alla fine dell'ultima riga. Inoltre, vedere la migliore risposta su una questione connessa: stackoverflow.com/questions/16222530/...
GCB

346
Solo per fare qualche chiacchiera in più, in realtà non ha scritto "nuova riga", ha scritto "nuova riga", che è corretto.
Sindrenm,

5
non familiare, ma mi chiedo davvero perché il numero di casi in cui quella newline superflua sta effettivamente rompendo le cose è un po 'troppo alto per i miei gusti
tobibeer

2
Attualmente sto utilizzando i flussi Node.js per analizzare i dati di testo normale riga per riga e la mancanza di interruzioni di riga terminale è fastidiosa, poiché devo aggiungere ulteriore logica per quando il lato di input del flusso è terminato / chiuso per garantire che l'ultima riga venga elaborata.
Mark K Cowan,

23
Il modo in cui Unix considera il suo comportamento generale alla fine dei file è il seguente: \ n i caratteri non iniziano le linee; invece, li finiscono. Quindi, \ n è un terminatore di riga, non un separatore di riga. La prima riga (come tutte le righe) non ha bisogno di \ n per avviarla. L'ultima riga (come tutte le righe) ha bisogno di un \ n per terminarla. Un \ n alla fine del file non crea una riga aggiuntiva. A volte, tuttavia, gli editor di testo aggiungono una riga vuota visibile lì. Anche emacs lo fa, facoltativamente .
MarkDBlackwell,

Risposte:


1383

Perché è così che lo standard POSIX definisce una linea :

Linea 3.206
Una sequenza di zero o più caratteri non <newline> più un carattere <newline> che termina.

Pertanto, le linee che non terminano con un carattere di nuova riga non sono considerate linee effettive. Ecco perché alcuni programmi hanno problemi nell'elaborazione dell'ultima riga di un file se non è terminato a capo.

C'è almeno un grande vantaggio in questa linea guida quando si lavora su un emulatore di terminale: tutti gli strumenti Unix prevedono questa convenzione e lavorano con essa. Ad esempio, quando si concatenano file con cat, un file terminato da newline avrà un effetto diverso da uno senza:

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

E, come dimostra anche l'esempio precedente, quando si visualizza il file sulla riga di comando (ad es. Via more), un file con terminazione di nuova riga produce una visualizzazione corretta. Un file terminato in modo errato potrebbe essere confuso (seconda riga).

Per coerenza, è molto utile seguire questa regola - altrimenti farebbe un lavoro extra quando si ha a che fare con gli strumenti Unix predefiniti.


Pensaci diversamente: se le linee non sono terminate da newline, creare comandi come catutili è molto più difficile: come fai un comando per concatenare i file in modo tale che

  1. mette l'inizio di ogni file su una nuova riga, che è quello che vuoi il 95% delle volte; ma
  2. permette di unire l'ultima e la prima riga di due file, come nell'esempio sopra tra b.txte c.txt?

Naturalmente questo è risolvibile, ma è necessario rendere l'uso di catpiù complesso (aggiungendo argomenti posizionali nella riga di comando, ad esempio cat a.txt --no-newline b.txt c.txt), e ora il comando anziché ogni singolo file controlla come viene incollato insieme ad altri file. Questo non è quasi certamente conveniente.

... O è necessario introdurre un carattere sentinella speciale per contrassegnare una linea che dovrebbe essere continuata anziché terminata. Bene, ora sei bloccato con la stessa situazione di POSIX, tranne che invertito (continuazione della linea anziché carattere di terminazione della linea).


Ora, su sistemi non compatibili con POSIX (al giorno d'oggi principalmente Windows), il punto è controverso: i file generalmente non terminano con una nuova riga e la definizione (informale) di una riga potrebbe essere ad esempio "testo separato da nuove righe" (notare l'enfasi). Questo è del tutto valido. Tuttavia, per i dati strutturati (ad es. Codice di programmazione) rende l'analisi più minimamente più complicata: generalmente significa che i parser devono essere riscritti. Se un parser è stato originariamente scritto tenendo presente la definizione POSIX, potrebbe essere più semplice modificare il flusso di token anziché il parser; in altre parole, aggiungere un token "newline artificiale" alla fine dell'input.


9
Anche se ora è poco pratico da correggere, chiaramente POSIX ha commesso un errore nel definire la linea, come prova del numero di domande riguardanti questo problema. Una riga avrebbe dovuto essere definita come zero o più caratteri terminati da <eol>, <eof> o <eol> <eof>. La complessità del parser non è una preoccupazione valida. La complessità, ove possibile, dovrebbe essere spostata dalla testa dei programmatori e nella libreria.
Doug Coburn,

23
@DougCoburn Questa risposta aveva una discussione esaustiva e tecnica che spiegava perché questo è sbagliato e perché POSIX ha fatto la cosa giusta. Sfortunatamente questi commenti sono stati apparentemente recentemente cancellati da un moderatore troppo zelante. In breve, non si tratta di analizzare la complessità; piuttosto, la tua definizione rende molto più difficile creare strumenti come catutili e coerenti.
Konrad Rudolph,

8
@Leon La regola POSIX riguarda la riduzione dei casi limite. E lo fa magnificamente. In realtà sono un po 'smarrito dal modo in cui le persone non riescono a capirlo: è la definizione più semplice possibile e coerente di una linea.
Konrad Rudolph,

6
@BT Penso che tu stia supponendo che il mio esempio di un flusso di lavoro più conveniente sia il motivo dietro la decisione. Non lo è, è solo una conseguenza. Il motivo è che la regola POSIX è la regola più semplice e che semplifica la gestione delle linee in un parser. L'unica ragione per cui stiamo discutendo è che Windows lo fa in modo diverso e che, di conseguenza, ci sono numerosi strumenti che falliscono sui file POSIX. Se tutti facessero POSIX, non ci sarebbero problemi. Eppure le persone si lamentano di POSIX, non di Windows.
Konrad Rudolph,

7
@BT Mi riferisco solo a Windows per sottolineare i casi in cui le regole POSIX non hanno senso (in altre parole, ti stavo gettando un osso). Sono più che felice di non menzionarlo mai più in questa discussione. Ma poi la tua affermazione ha ancora meno senso: sulle piattaforme POSIX semplicemente non ha senso discutere file di testo con convenzioni di fine linea diverse, perché non c'è motivo di produrle. Qual è il vantaggio? Non c'è letteralmente nessuno. - In sintesi, non capisco davvero l'odio che questa risposta (o la regola POSIX) sta generando. Ad essere sinceri, è completamente irrazionale.
Konrad Rudolph,

282

Ogni riga deve essere terminata con un carattere di nuova riga, incluso l'ultimo. Alcuni programmi hanno problemi nell'elaborazione dell'ultima riga di un file se non è terminato da nuova riga.

GCC lo avverte non perché non è in grado di elaborare il file, ma perché deve far parte dello standard.

Lo standard del linguaggio C dice che un file sorgente che non è vuoto deve finire con un carattere di nuova riga, che non deve essere immediatamente preceduto da una barra rovesciata.

Poiché si tratta di una clausola "deve", dobbiamo emettere un messaggio diagnostico per violazione di questa regola.

Questo è nella sezione 2.1.1.2 della norma ANSI C 1989. Sezione 5.1.1.2 della norma ISO C 1999 (e probabilmente anche della norma ISO C 1990).

Riferimento: l'archivio di posta GCC / GNU .


17
si prega di scrivere buoni programmi quindi che consentano di inserire quella nuova riga quando necessario durante l'elaborazione o siano in grado di gestire correttamente quelli "mancanti" ... che, in effetti, non mancano
tobibeer,

4
@BilltheLizard, Quali sono alcuni esempi di "Alcuni programmi hanno problemi nell'elaborazione dell'ultima riga di un file se non è terminata la nuova riga" ?
Pacerier

4
@Pacerier wc -lnon conterà l'ultima riga di un file se non è terminato a capo. Inoltre, catunirà l'ultima riga di un file con la prima riga del file successivo in una se l'ultima riga del primo file non è terminata a nuova riga. Praticamente qualsiasi programma che cerca newline come delimitatore ha il potenziale per rovinare tutto.
Bill the Lizard,

2
@BilltheLizard, voglio dire, wcè già stato menzionato ....
Pacerier

2
@BilltheLizard, Mio male, per chiarire: quali sono alcuni esempi di programmi che hanno problemi nell'elaborazione dell'ultima riga di un file se non è terminata la nuova riga (oltre a quelli che sono già stati menzionati in massa sul thread come cate wc)?
Pacerier,

116

Questa risposta è un tentativo di risposta tecnica piuttosto che opinione.

Se vogliamo essere puristi POSIX, definiamo una linea come:

Una sequenza di zero o più caratteri non <newline> più un carattere <newline> che termina.

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

Una linea incompleta come:

Una sequenza di uno o più caratteri non <newline> alla fine del file.

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

Un file di testo come:

Un file che contiene caratteri organizzati in zero o più righe. Le righe non contengono caratteri NUL e nessuna può superare i {LINE_MAX} byte di lunghezza, incluso il carattere <newline>. Sebbene POSIX.1-2008 non distingua tra file di testo e file binari (vedere lo standard ISO C), molte utility producono output prevedibili o significativi solo quando si opera su file di testo. Le utility standard che hanno tali restrizioni specificano sempre "file di testo" nelle loro sezioni STDIN o INPUT FILES.

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

Una stringa come:

Una sequenza contigua di byte terminata da e incluso il primo byte null.

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

Da ciò, quindi, possiamo derivare che l'unica volta in cui potremmo potenzialmente incontrare qualsiasi tipo di problema è se trattiamo il concetto di una riga di un file o di un file come file di testo (essendo che un file di testo è un'organizzazione pari a zero o più righe e una riga che conosciamo deve terminare con una <newline>).

Caso in questione: wc -l filename.

Dal wcmanuale si legge:

Una linea è definita come una stringa di caratteri delimitati da un carattere <newline>.

Quali sono le implicazioni per i file JavaScript, HTML e CSS allora che sono file di testo ?

Nei browser, IDE moderni e altre applicazioni front-end non ci sono problemi con saltare EOL su EOF. Le applicazioni analizzeranno correttamente i file. Dal momento che non tutti i sistemi operativi devono essere conformi allo standard POSIX, pertanto non sarebbe pratico per gli strumenti non OS (ad esempio i browser) gestire i file secondo lo standard POSIX (o qualsiasi standard a livello di sistema operativo).

Di conseguenza, possiamo essere relativamente certi che EOL presso EOF non avrà praticamente alcun impatto negativo a livello di applicazione, indipendentemente dal fatto che sia in esecuzione su un sistema operativo UNIX.

A questo punto possiamo affermare con certezza che saltare EOL su EOF è sicuro quando si ha a che fare con JS, HTML, CSS sul lato client. In realtà, possiamo affermare che la minimizzazione di uno di questi file, che non contiene <newline> è sicura.

Possiamo fare un ulteriore passo avanti e dire che anche per NodeJS non può aderire allo standard POSIX in quanto può essere eseguito in ambienti non POSIX compatibili.

Cosa ci rimane allora? Strumenti a livello di sistema.

Ciò significa che gli unici problemi che possono sorgere riguardano gli strumenti che fanno uno sforzo per aderire alla loro funzionalità alla semantica di POSIX (ad es. Definizione di una linea come mostrato in wc).

Anche così, non tutte le shell aderiranno automaticamente a POSIX. Bash, ad esempio, per impostazione predefinita non si comporta POSIX. C'è un interruttore per attivarlo: POSIXLY_CORRECT.

Spunti di riflessione sul valore di EOL <newline>: https://www.rfc-editor.org/old/EOLstory.txt

Rimanendo sulla pista degli utensili, a tutti gli effetti pratici, consideriamo questo:

Lavoriamo con un file che non ha EOL. Al momento della stesura di questo documento, il file in questo esempio è un JavaScript minimizzato senza 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

Si noti che la catdimensione del file è esattamente la somma delle sue singole parti. Se la concatenazione dei file JavaScript è un problema per i file JS, la preoccupazione più appropriata sarebbe quella di avviare ogni file JavaScript con un punto e virgola.

Come qualcun altro ha menzionato in questo thread: cosa succede se si desidera catdue file il cui output diventa solo una riga anziché due? In altre parole, catfa quello che dovrebbe fare.

L' mandi catsola lettura menzioni d'ingresso fino a EOF, non <newline>. Si noti che lo -nswitch di catstamperà anche una linea terminata non <nuova> (o linea incompleta ) come linea - essendo che il conteggio inizia da 1 (secondo il man.)

-n Numerare le righe di output, iniziando da 1.

Ora che comprendiamo come POSIX definisce una linea , questo comportamento diventa ambiguo o davvero non conforme.

Comprendere lo scopo e la conformità di un determinato strumento aiuterà a determinare quanto sia fondamentale terminare i file con un EOL. In C, C ++, Java (JAR), ecc ... alcuni standard dettano una nuova linea per la validità - non esiste uno standard simile per JS, HTML, CSS.

Ad esempio, invece di usarne wc -l filenameuno si potrebbe fare awk '{x++}END{ print x}' filename, e sii certo che il successo dell'attività non è compromesso da un file che potremmo voler elaborare e che non abbiamo scritto (ad esempio una libreria di terze parti come la JS minimizzata che curld) - a meno che il nostro l'intenzione era davvero quella di contare le linee nel senso conforme a POSIX.

Conclusione

Ci saranno pochissimi casi d'uso reali in cui saltare EOL su EOF per determinati file di testo come JS, HTML e CSS avrà un impatto negativo, se non del tutto. Se facciamo affidamento sulla presenza di <newline>, stiamo limitando l'affidabilità dei nostri strumenti solo ai file che creiamo e ci apriamo a potenziali errori introdotti da file di terze parti.

Morale della storia: strumenti di ingegneria che non hanno la debolezza di fare affidamento su EOL presso EOF.

Sentiti libero di pubblicare casi d'uso quando si applicano a JS, HTML e CSS in cui possiamo esaminare in che modo saltare EOL ha un effetto negativo.


2
POSIX non è taggato nella domanda ... a proposito delle terminazioni di linea MVS / OS? o terminazioni di riga MS-DOS? A proposito, tutti i sistemi posix conosciuti consentono file di testo senza un finale di riga finale (nessun caso trovato di un sistema di rivendicazione conforme a posix su cui "file di testo" ha un trattamento speciale nel kernel per inserire una nuova riga appropriata nel caso in cui non abbia it)
Luis Colorado,

62

Potrebbe essere correlato alla differenza tra :

  • file di testo (ogni riga dovrebbe terminare con una fine riga)
  • file binario (non ci sono vere "righe" di cui parlare e la lunghezza del file deve essere preservata)

Se ogni riga termina con una fine riga, questo evita, ad esempio, che concatenare due file di testo farebbe eseguire l'ultima riga della prima alla prima riga della seconda.

Inoltre, un editor può verificare al caricamento se il file termina in una riga di fine, lo salva nella sua opzione locale 'eol' e lo usa durante la scrittura del file.

Alcuni anni fa (2005), molti editori (ZDE, Eclipse, Scite, ...) "dimenticarono" quell'EOL finale, che non era molto apprezzato .
Non solo, ma hanno interpretato in modo errato quella EOL finale, come "avvia una nuova riga" e in realtà iniziano a visualizzare un'altra riga come se esistesse già.
Ciò era molto visibile con un file di testo "corretto" con un editor di testo ben educato come vim, rispetto all'apertura in uno dei suddetti editor. Ha visualizzato una riga aggiuntiva sotto l'ultima riga reale del file. Vedi qualcosa del genere:

1 first line
2 middle line
3 last line
4

11
+1. Ho trovato questa domanda SO durante questo stesso problema. È molto fastidioso per Eclipse mostrare questa "falsa" ultima riga, e se lo rimuovo, allora git (e tutti gli altri strumenti unix che prevedono EOL) si lamentano. Inoltre, si noti che questo non è solo nel 2005: Eclipse 4.2 Juno presenta ancora questo problema.
MestreLion,

@MestreLion, Continuazione a stackoverflow.com/questions/729692/...
Pacerier

46

Alcuni strumenti si aspettano questo. Ad esempio, si wcaspetta questo:

$ echo -n "Line not ending in a new line" | wc -l
0
$ echo "Line ending with a new line" | wc -l
1

22
Non direi "alcuni", dico che molti strumenti si aspettano che per i file di testo, se non tutti. cat, git, diff, wc, grep, sed ... la lista è enorme
MestreLion

Forse si potrebbe dire che wcnon lo si aspetta , in quanto sta semplicemente lavorando all'interno della definizione POSIX di "linea" in contrapposizione alla comprensione intuitiva di "linea" della maggior parte delle persone.
Guildenstern,

@Guildenstern La definizione intuitiva sarebbe per la wc -lstampa 1in entrambi i casi, ma alcune persone potrebbero dire che il secondo caso dovrebbe essere stampato 2.
Flimm,

@Flimm Se pensi \na un terminatore di linea, piuttosto che a un separatore di linea, come fa POSIX / UNIX, aspettarsi che il secondo caso stampi 2 è assolutamente folle.
punto

21

Fondamentalmente ci sono molti programmi che non elaboreranno i file correttamente se non ottengono l'EOF EOL finale.

GCC ti avverte perché è previsto come parte dello standard C. (apparentemente la sezione 5.1.1.2)

Avviso compilatore "No newline alla fine del file"


5
GCC non è in grado di elaborare il file, ma deve dare l'avvertimento come parte dello standard C.
Bill the Lizard,

IIRC, MSVC 2005 si è lamentato dei file C che si sono conclusi con linee incomplete e probabilmente si sono rifiutati di compilarli.
Mark K Cowan,

16

Ciò ha origine fin dai primissimi tempi in cui venivano utilizzati semplici terminali. Il carattere newline è stato utilizzato per attivare un 'flush' dei dati trasferiti.

Oggi, il carattere newline non è più richiesto. Certo, molte app hanno ancora problemi se la newline non è presente, ma considererei un bug in quelle app.

Se tuttavia hai un formato di file di testo in cui è richiesta la nuova riga, otterrai una semplice verifica dei dati molto economica: se il file termina con una riga che non ha una nuova riga alla fine, sai che il file è interrotto. Con solo un byte in più per ogni linea, è possibile rilevare file rotti con elevata precisione e quasi nessun tempo di CPU.


15
al giorno d'oggi la nuova riga in EOF per i file di testo potrebbe non essere un requisito, ma è una convenzione utile che fa funzionare la maggior parte degli strumenti unix insieme a risultati coerenti. Non è affatto un bug.
MestreLion,

14
Molti di noi non usano affatto gli strumenti Unix e non ci interessa.
DaveWalley,

12
Non sono solo strumenti di Unix, qualsiasi strumento funzionerà meglio e / o sarà codificato più semplicemente se può assumere formati di file ragionevoli.
Sam Watkins,

2
@Sam Watkins Concordare che avere formati semplici e ben definiti è buono. Tuttavia, il codice deve ancora verit, e non assumere, i dati sono conformi al formato.
chux - Ripristina Monica il

8
@MestreLion Questa è un'eredità inutile da un insieme di strumenti cattivi conformi a standard stupidi. Questi artefatti della programmazione estremista (vale a dire il file di ogni cosa! Tutto dovrebbe parlare in chiaro!) Non morirono subito dopo la loro invenzione perché erano gli unici strumenti disponibili del genere in un certo momento della storia. C è stato sostituito da C ++, non fa parte di POSIX, non richiede EOL su EOF e il suo utilizzo è (ovviamente) scoraggiato da * nix luddists.
polkovnikov.ph,

14

Un caso d'uso separato: quando il tuo file di testo è controllato dalla versione (in questo caso specificamente sotto git sebbene si applichi anche ad altri). Se il contenuto viene aggiunto alla fine del file, la riga che era in precedenza l'ultima riga sarà stata modificata per includere un carattere di nuova riga. Ciò significa che blameil file ing per scoprire quando l'ultima riga è stata modificata mostrerà l'aggiunta del testo, non il commit prima che tu volessi davvero vedere.


1
diff e blame dovrebbero essere aggiornati per rilevare "nuove righe" anziché "newline" ( \n). Problema risolto.
Andrew,

1
È possibile utilizzare il tag -w per ignorare le modifiche agli spazi bianchi, ma non sono quelle predefinite.
Robin Whittleton,

11

Oltre ai motivi pratici di cui sopra, non mi sorprenderebbe se i creatori di Unix (Thompson, Ritchie, et al.) Oi loro predecessori Multics si rendessero conto che esiste un motivo teorico per usare i terminatori di linea anziché i separatori di linea: Con la linea terminatori, è possibile codificare tutti i possibili file di linee. Con i separatori di linea, non c'è differenza tra un file di zero linee e un file contenente una singola riga vuota; entrambi sono codificati come file contenente zero caratteri.

Quindi, i motivi sono:

  1. Perché è così che POSIX lo definisce.
  2. Perché alcuni strumenti se lo aspettano o "si comportano male" senza di essa. Ad esempio, wc -lnon conterà una "linea" finale se non termina con una nuova riga.
  3. Perché è semplice e conveniente. Su Unix, catfunziona e funziona senza complicazioni. Copia solo i byte di ciascun file, senza alcuna necessità di interpretazione. Non credo che ci sia un DOS equivalente a cat. L'uso copy a+b cfinirà per fondere l'ultima riga del file acon la prima riga del file b.
  4. Perché un file (o flusso) di zero linee può essere distinto da un file di una riga vuota.

11

Me lo sono chiesto da anni. Ma oggi ho trovato una buona ragione.

Immagina un file con un record su ogni riga (es: un file CSV). E che il computer stava scrivendo i record alla fine del file. Ma si è schiantato improvvisamente. Accidenti era l'ultima riga completa? (non è una bella situazione)

Ma se terminiamo sempre l'ultima riga, lo sapremmo (controlla semplicemente se l'ultima riga è terminata). Altrimenti dovremmo probabilmente scartare l'ultima riga ogni volta, solo per sicurezza.


10

Presumibilmente semplicemente che un codice di analisi si aspettava che fosse lì.

Non sono sicuro che lo considererei una "regola", e certamente non è qualcosa a cui aderisco religiosamente. Il codice più sensato saprà come analizzare il testo (comprese le codifiche) riga per riga (qualsiasi scelta di terminazioni di riga), con o senza una nuova riga sull'ultima riga.

Anzi - se finisci con una nuova linea: esiste (in teoria) una linea finale vuota tra l'EOL e l'EOF? Uno su cui riflettere ...


12
Non è una regola, è una convenzione: una linea è qualcosa che termina con una fine linea . Quindi no, non esiste una "linea finale vuota" tra EOL ed EOF.
MestreLion,

4
@MestreLion: Ma il personaggio in questione non si chiama "end-of-line", si chiama "newline" e / o "linefeed". Un separatore di linea, non un terminatore di linea. E il risultato è un'ultima riga vuota.
Ben Voigt,

2
Nessuno strumento (sano) conterebbe l'ultimo EOL (CR, LF, ecc.) Di un file come una riga vuota aggiuntiva. E tutti gli strumenti POSIX non conteggeranno gli ultimi caratteri di un file come una linea se non c'è EOL finale. Indipendentemente dal fatto che il nome del carattere EOL sia "avanzamento riga" o "ritorno a capo" (non esiste un carattere denominato "newline"), per tutte le pupille pratiche gli strumenti sensibili lo trattano come un terminatore di riga , non come un separatore di riga .
MestreLion,

2
@MestreLion, sei sicuro che "terminatore di linea" sia sano? Prendi alcuni non programmatori e fai un rapido sondaggio. Ti accorgerai rapidamente che il concetto di linee è più vicino al concetto di "separatori di linee". Il concetto di "terminatore di linea" è semplicemente strano .
Pacerier,

4
@Sahuagin: Questa non è la mia opinione, ecco come lo standard POSIX definisce una linea. Un file vuoto con 0 byte ha 0 linee, quindi non EOL, e un file da essere considerata come avente solo una singola linea, vuoto, si fa necessario un EOL. Si noti inoltre che ciò è rilevante solo se si desidera contare le righe su un file, poiché ovviamente qualsiasi editor consente di "passare" alla riga successiva (o alla prima) indipendentemente dal fatto che sia già presente un EOL.
MestreLion,

10

C'è anche un problema di programmazione pratica con i file privi di nuove righe alla fine: il readBash integrato (non conosco altre readimplementazioni) non funziona come previsto:

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

Questo stampa solofoo ! Il motivo è che quando readincontra l'ultima riga, scrive il contenuto $linema restituisce il codice di uscita 1 perché ha raggiunto EOF. Questo interrompe il whileciclo, quindi non raggiungiamo mai la echo $lineparte. Se vuoi gestire questa situazione, devi fare quanto segue:

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

Cioè, esegui echoif se readfallito a causa di una riga non vuota alla fine del file. Naturalmente, in questo caso ci sarà una nuova riga in più nell'output che non era nell'input.


9

Perché i file (di testo) dovrebbero terminare con una nuova riga?

Così espresso da molti, perché:

  1. Molti programmi non si comportano bene o falliscono senza di essa.

  2. Anche i programmi che gestiscono bene un file mancano di un finale '\n', la funzionalità dello strumento potrebbe non soddisfare le aspettative dell'utente, il che può essere poco chiaro in questo caso d'angolo.

  3. I programmi raramente non consentono final '\n'(non ne conosco nessuno).


Tuttavia, ciò pone la domanda successiva:

Cosa dovrebbe fare il codice sui file di testo senza una nuova riga?

  1. Più importante: non scrivere codice che presuppone che un file di testo termini con una nuova riga . Supponendo che un file sia conforme a un formato porta a corruzione dei dati, attacchi di hacker e arresti anomali. Esempio:

    // 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 '\n'è necessario il finale finale , avvisare l'utente della sua assenza e delle azioni intraprese. IOW, convalida il formato del file. Nota: questo può includere un limite alla lunghezza massima della linea, alla codifica dei caratteri, ecc.

  3. Definire chiaramente, documentare, la gestione del codice di un finale mancante '\n'.

  4. Non, per quanto possibile, generare un file in cui manca la fine '\n'.


4

È molto tardi qui, ma ho appena affrontato un bug nell'elaborazione dei file e questo è venuto perché i file non terminavano con una nuova riga vuota. Stavamo elaborando file di testo sede sedomettevamo l'ultima riga dall'output che causava una struttura json non valida e l'invio dello stato del resto del processo.

Tutto quello che stavamo facendo era:

C'è un file di esempio che dice: foo.txtcon alcuni jsoncontenuti al suo interno.

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

Il file è stato creato nella macchina delle vedove e gli script delle finestre stavano elaborando quel file usando i comandi di PowerShell. Tutto bene.

Quando abbiamo elaborato lo stesso file usando il sedcomandosed 's|value|newValue|g' foo.txt > foo.txt.tmp

Il file appena generato era

[{
    someProp: value
},
{
    someProp: value

e boom, ha fallito il resto dei processi a causa del JSON non valido.

Quindi è sempre una buona pratica terminare il file con una nuova riga vuota.


3

Ho sempre avuto l'impressione che la regola venisse dai giorni in cui era difficile analizzare un file senza terminare una nuova riga. Cioè, si finirà per scrivere il codice in cui una fine della linea è stata definita dal carattere EOL o EOF. Era solo più semplice supporre che una linea terminasse con EOL.

Comunque credo che la regola derivi dai compilatori C che richiedono la newline. E come sottolineato nell'avvertimento del compilatore “Nessuna nuova riga alla fine del file” , #include non aggiungerà una nuova riga.


0

Immagina che il file sia in fase di elaborazione mentre il file è ancora generato da un altro processo.

Potrebbe avere a che fare con quello? Un flag che indica che il file è pronto per essere elaborato.


-4

Personalmente mi piacciono le nuove righe alla fine dei file di codice sorgente.

Potrebbe avere la sua origine con Linux o tutti i sistemi UNIX per quella materia. Ricordo che c'erano errori di compilazione (gcc se non sbaglio) perché i file di codice sorgente non terminavano con una nuova riga vuota. Perché è stato fatto in questo modo si lascia a chiedersi.


-6

IMHO, è una questione di stile e opinione personale.

Ai vecchi tempi, non avevo messo quella nuova riga. Un personaggio salvato significa più velocità attraverso quel modem 14.4K.

Successivamente, ho inserito quella nuova riga in modo che sia più facile selezionare la riga finale usando shift + downarrow.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.