it-swarm.it

A che serve aggiungere una nuova riga alla fine di un file?

Alcuni compilatori (in particolare quelli C o C++) forniscono avvisi su:

No new line at end of file

Ho pensato che questo sarebbe stato un problema solo per i programmatori C, ma github visualizza un messaggio nella vista commit:

\ No newline at end of file

per un PHP.

Capisco la cosa del preprocessore spiegata in questo thread , ma cosa c'entra questo con PHP? È la stessa cosa include() o è correlata all'argomento \r\n Vs \n?

Qual è il punto di avere una nuova riga alla fine di un file?

197
Philipp Stephan

Non si tratta di aggiungere una nuova riga alla fine di un file, non si tratta di rimuovere la nuova riga che dovrebbe essere lì.

Un file di testo , sotto unix, è costituito da una serie di righe , ognuno dei quali termina con un carattere di nuova riga (\n). Un file che non è vuoto e non termina con una nuova riga non è quindi un file di testo.

Le utility che dovrebbero funzionare su file di testo potrebbero non far fronte bene ai file che non terminano con una nuova riga; i programmi di utilità storici Unix potrebbero ignorare il testo dopo l'ultima riga, ad esempio. GNU le utility hanno una politica di comportamento decente con i file non di testo, così come la maggior parte delle altre utility moderne, ma potresti comunque riscontrare comportamenti strani con file che sono manca una nuova riga finale¹.

Con GNU diff, se uno dei file confrontati termina con una nuova riga ma non con l'altro, è importante notare questo fatto. Poiché diff è orientato alla linea, non può indicare questo memorizzando una nuova riga per uno dei file ma non per gli altri - le nuove righe sono necessarie per indicare dove ogni riga nel file diff inizia e finisce. Quindi diff usa questo testo speciale \ No newline at end of file per differenziare un file che non è terminato in una nuova riga da un file che lo ha fatto.

A proposito, in un contesto C, un file sorgente è similmente formato da una serie di linee. Più precisamente, un'unità di traduzione viene visualizzata in un'implementazione definita come una serie di linee, ognuna delle quali deve terminare con un carattere di nuova riga ( n1256 §5.1.1.1). Sui sistemi unix, la mappatura è semplice. Su DOS e Windows, ogni CR LF (\r\n) è mappato su una nuova riga (\n; questo è ciò che accade sempre quando si legge un file aperto come testo su questi sistemi operativi). Ci sono alcuni sistemi operativi là fuori che non hanno un carattere di nuova riga, ma invece hanno record di dimensioni fisse o variabili; su questi sistemi, la mappatura dai file alla sorgente C introduce un \n alla fine di ogni record. Anche se questo non è direttamente rilevante per unix, significa che se copi un file sorgente C che manca la sua nuova riga finale in un sistema con file di testo basati su record, quindi copiarlo di nuovo, finirai con l'incompleto ultima linea troncata nella conversione iniziale o una nuova riga aggiuntiva attaccata su di essa durante la conversione inversa.

¹ Esempio: l'output di GNU termina sempre con una nuova riga. Quindi se nel file foo manca la sua nuova riga finale, troverai che sort foo | wc -c riporta un carattere in più di cat foo | wc -c.

Non necessariamente il motivo, ma una conseguenza pratica dei file che non terminano con una nuova riga:

Considera cosa succederebbe se volessi elaborare diversi file usando cat. Ad esempio, se si desidera trovare la parola foo all'inizio della riga tra 3 file:

cat file1 file2 file3 | grep -e '^foo'

Se la prima riga in file3 inizia con foo, ma file2 non ha un finale \n Dopo l'ultima riga, questa occorrenza non verrà trovata da grep, perché l'ultima riga in file2 e il la prima riga in file3 verrebbe vista da grep come una singola riga.

Quindi, per coerenza e per evitare sorprese, cerco di mantenere i miei file finendo sempre con una nuova riga.

48
Sergio Acosta

Ci sono due aspetti:

  1. Ci sono/erano alcuni compilatori C che non possono analizzare l'ultima riga se non termina con una nuova riga. Lo standard C specifica che un file C dovrebbe terminare con una nuova riga (C11, 5.1.1.2, 2.) e che un'ultima riga senza una nuova riga produce un comportamento indefinito (C11, J.2, 2a voce). Forse per ragioni storiche, perché alcuni venditori di un tale compilatore facevano parte del comitato quando fu scritto il primo standard. Quindi l'avvertimento di GCC.

  2. diff programmi (come quelli utilizzati da git diff, github ecc.) mostrano differenze riga per riga tra i file. Di solito stampano un messaggio quando un solo file termina con una nuova riga perché altrimenti non vedresti questa differenza. Ad esempio, se l'unica differenza tra due file è la presenza dell'ultimo carattere di nuova riga, senza il suggerimento sembrerebbe che entrambi i file fossero uguali, quando diff e cmp restituiscono un'uscita- codice diseguale successo e checksum dei file (ad es. tramite md5sum) non corrispondono.

17
maxschlepzig

Il \ No newline at end of file Che ottieni da github appare alla fine di una patch (in formato diff , vedi la nota alla fine della sezione "Formato unificato").

I compilatori non si preoccupano se c'è una nuova riga o meno alla fine di un file, ma git (e le utilità diff/patch) devono tenerne conto . Ci sono molte ragioni per questo. Ad esempio, dimenticare di aggiungere o rimuovere una nuova riga alla fine di un file cambierebbe il suo hashsum (md5sum/sha1sum). Inoltre, i file non sono sempre programmi e un \n Finale potrebbe fare la differenza.

Nota : A proposito dell'avvertimento dei compilatori C, suppongo che insistano per una nuova riga finale ai fini della compatibilità con le versioni precedenti. I compilatori molto vecchi potrebbero non accettare l'ultima riga se non termina con \n (O altra sequenza di caratteri di fine riga dipendente dal sistema).

12

C'è anche il punto di mantenere la cronologia delle differenze. Se un file termina senza un carattere di nuova riga, l'aggiunta di qualcosa alla fine del file verrà visualizzato dalle utility diff come modifica dell'ultima riga (perché \n viene aggiunto ad esso).

Ciò potrebbe causare risultati indesiderati con comandi come git blame e hg annotate.

6
Hosam Aly

POSIX, questo è un insieme di standard specificati dall'IEEE per mantenere la compatibilità tra i sistemi operativi.

Uno dei quali è la definizione di una "linea" che è una sequenza di zero o più non caratteri più un carattere di nuova riga che termina.

Quindi, affinché l'ultima riga sia riconosciuta come una "linea" effettiva, dovrebbe avere un carattere di nuova riga che termina.

Questo è importante se dipendi dagli strumenti del sistema operativo per dire il conteggio delle righe o dividere/aiutare ad analizzare il tuo file. Dato PHP è un linguaggio di script, è del tutto possibile soprattutto nei suoi primi giorni o anche ora (non ho idea/postulazione) aveva dipendenze del sistema operativo del genere.

In realtà, la maggior parte dei sistemi operativi non è completamente conforme a POSIX e gli umani non sono simili alla macchina o si preoccupano nemmeno di terminare nuove linee. Quindi, per la maggior parte delle cose, è una smorgasbord di tutto ciò che si prende cura di esso, che avverte o semplicemente che l'ultimo pezzo di testo sia davvero una linea, quindi includilo.

4
user3379747