2010-07-16 12 views
9

Ho un numero enorme di file di origine che mancano tutti di una nuova riga alla fine.Come risolvere l'avviso "No newline alla fine del file" per molti file?

Come si aggiunge automaticamente una nuova riga alla fine di ciascuna di esse?

Alcuni potrebbero già avere una nuova riga, pertanto è necessario aggiungerli se necessario.

Probabilmente non sto cercando il codice, di per sé, ma solo qualcosa che posso eseguire in Terminal per aggiungere le nuove righe necessarie (o qualche tipo di strumento di programmazione o di sviluppo).

risposta

3

Convertire la risposta di Norman a una fodera singola per comodità.

for i in * ; do echo $i; \ 
if diff /dev/null "$i" | tail -1 | \ 
    grep '^\\ No newline' > /dev/null; then echo >> "$i"; \ 
fi; done 

Sostituire * con qualsiasi modello di file che si desidera, ad esempio *.c

E un altro al solo dirvi quali file sono rotti:

for i in * ; do \ 
if diff /dev/null "$i" | tail -1 | \ 
    grep '^\\ No newline' > /dev/null; then echo $i; \ 
fi; done 
+0

Nessuna delle soluzioni funziona per me –

+1

Se vuoi che vada in modo ricorsivo, puoi scambiare '*' con '$ (find. -type f)' o '$ (trova -type f -name )' – durron597

7

Se si ha accesso a strumenti Unix, è possibile eseguire diff per scoprire quali file mancano una nuova riga e quindi aggiungere che:

#!/bin/sh 
for i 
do 
    if diff /dev/null "$i" | tail -1 | grep '^\\ No newline' > /dev/null 
    then 
    echo >> "$i" 
    fi 
done 

sto contando su diff per produrre il messaggio con un \ in la prima colonna, tail, per darmi l'ultima riga dell'output di diff e grep per dirmi se l'ultima riga è il messaggio che sto cercando. Se tutto ciò funziona, lo echo produce una nuova riga e lo >> lo aggiunge al file "$i". Le virgolette intorno a "$i" assicurano che le cose funzionino ancora se il nome del file contiene degli spazi.

+2

Non male, ma grep restituisce un messaggio localizzato, come "\ Brak znaku nowej linii (ecc.)". Inoltre, il diff produce l'intero file. Io userei 'tail -1 $ f | grep '\ n'' per la condizione (funziona sulla mia scatola). –

+0

@TomaszGandor: 'tail -1 nomefile | grep '\ n' sembra restituire sempre un falso risultato sul mio mac indipendentemente dal fatto che esista o meno una nuova riga finale. – Gino

2

OK, dopo aver accusato nei commenti, v'è la mia soluzione migliore primo luogo, si vuole sapere, quali file sono mancanti a capo:

find -type f -exec sh -c "tail -1 {} | xxd -p | tail -1 | grep -v 0a$" ';' -print 

Non super veloce (chiamare un paio di processi per ogni file), ma è OK per l'uso pratico.

Ora, quando si dispone di esso, si può anche aggiungere il ritorno a capo, con un altro -exec:

find -type f -exec sh -c "tail -1 {} | xxd -p | tail -1 | grep -v 0a$" ';' -exec sh -c "echo >> {}" ';' 

possibili grattacapi:

  • se i nomi dei file sono cattivi, per esempio hanno spazi, potrebbe essere necessario tail -1 \"{}\". Oppure trova giusto?

  • è possibile aggiungere ulteriori filtri per trovare, ad esempio -name \*py o simili.

  • pensare a possibili problemi con le newline DOS/Unix prima dell'uso (risolvilo prima).

EDIT:

Se non vi piace l'output di questi comandi (facendo eco alcuni hex), aggiungere -q a grep:

find -type f -exec sh -c "tail -1 {} | xxd -p | tail -1 | grep -q -v 0a$" ';' -print 
find -type f -exec sh -c "tail -1 {} | xxd -p | tail -1 | grep -q -v 0a$" ';' -exec sh -c "echo >> {}" ';' 
+1

Questo è * enorme * eccessivo. – tripleee

0

causa Per comandare localizzazione Tim e Norman risposta Sarà migliorato usando il prefisso "LANG = C" per avere la possibilità di abbinare il pattern "No newline" con ogni sistema che ha parametri regionali

Questo assicura una linea vuota finale ad ogni file mettere sulla riga di comando di questo script:

#!/bin/sh -f 
for i in $* ; do echo $i; \ 
if LANG=C diff /dev/null "$i" | tail -1 | \ 
    grep '^\\ No newline' > /dev/null; then echo >> "$i"; \ 
fi; done 

E questo script rileva i file privi di esso:

#!/bin/sh -f 
for i in $* ; do \ 
if LANG=C diff /dev/null "$i" | tail -1 | \ 
    grep '^\\ No newline' > /dev/null; then echo $i; \ 
fi; done 
1

Prova ex-strada:

ex -s +"bufdo wq" *.c 

E ricorsivamente (con a new globbing option abilitato):

ex -s +"bufdo wq" **/*.c 

Questo è equivalente a vi -es. Cambia *.c per l'estensione del tuo interesse.

Il ex/vi aggiungerebbe automaticamente newline su save se non è presente.

0

Dopo aver trovato lo strumento, fare questo lavoro senza fortuna. Decido di scrivere il mio

Questo è il mio script python per fare quel lavoro

E 'solo aggiungere (\ r \ n) al file non contiene (\ n) alla fine del file di

https://github.com/tranhuanltv/append_newline

Usage: ./projects .c append_newline.py ./result_dir

Richieste Fai Pull se si vuole

+0

Questo è molto discutibile: la ricerca di -1 da END è OK, ma potresti facilmente mescolare le newline di Unix e DOS in questo modo ... –

0

sono sorpreso nessuno ha menzionato il fatto che molti semplici strumenti di elaborazione del testo come Awk aggiungeranno una nuova riga come effetto collaterale. Ecco un semplice ciclo che sovrascriverà un file solo se è stata effettivamente aggiunta una nuova riga.

for f in *; do 
    awk 1 "$f" >tmp 
    cmp -s tmp "$f" || mv tmp "$f" 
done 
rm -f tmp 

(Il file temporaneo è ovviamente un po 'di una verruca.)

Ideone demo: http://ideone.com/HpRHcx

0
pcregrep --recursive --exclude-dir=.git \ 
    --files-without-match --multiline '\n\z' . | 
    while read k ; do echo >> "$k"; done 

Ci sono diversi passaggi coinvolti qui:

  1. ricorsivamente trovare file
  2. rilevare quali file mancano di una nuova linea di uscita
  3. loop su ciascuno dei quei file
  4. Aggiungere la nuova riga

Fase 1 è tradizionalmente fatto con find (seguendo la tradizione Unix di "ogni strumento di fare una cosa e farlo bene"), ma dal momento che pcregrep ha il supporto incorporato, mi sento a mio agio con essa. Sto attento a non scherzare con la cartella .git.

Fase 2 è fatto con un'espressione regolare multilinea corrispondenti file che fare hanno un ritorno a capo finale, e la stampa i nomi dei file che non facciamo partita.

Il passaggio 3 viene eseguito con un ciclo while/read piuttosto che un per/in, poiché quest'ultimo non riesce per i nomi file con spazi e per elenchi di file estremamente lunghi.

Il passaggio 4 è un'eco semplice, seguendo l'approccio di @ norman-ramsey.

h/t @ anthony-bush https://stackoverflow.com/a/20687956/577438 per il suggerimento di pcregrep.

1

sto usando find invece di for f in * come è ricorsivo e la questione era di "enorme numero di file di origine".

Sto utilizzando anziché find -exec o xargs per motivi di prestazioni, salva ogni volta il processo di generazione di spawning.

Sto approfittando del fatto che l'operatore backtick sta restituendo l'output del comando "con qualsiasi newline finale cancellato" man bash, quindi per i file terminati correttamente il backtick sarà vuoto e l'eco verrà saltato.

La coppia find | read avrà esito negativo su nomi di file che contengono nuove righe, ma è facile da risolvere se necessario:

find -type f -print0 | while read -d $'\0' f; do [[ `tail -c1 "$f"` ]] && echo >> "$f"; done

0

Qui di seguito è la mia soluzione script bash. Prima controlla che il file sia un file di testo. Quindi, se si tratta di un file di testo, usa tail e od (octal dump) per vedere se l'ultimo carattere è il carattere newline.Se non lo è, allora aggiunge una nuova riga utilizzando eco:

item="$1" 

if file "$item" | egrep '\btext\b' > /dev/null 
then 
    if ! tail -c 1 "$item" | od -b -A n | egrep '\b012\b' > /dev/null 
    then 
     echo "(appending final newline to ${item})" 
     echo >> "$item" 
    fi 
fi 
1

una semplice correzione per i file "mancanti" di nuova riga alla fine del file è semplicemente sed; le seguenti correzioni al file "in-place" (usando l'opzione "-i"):

find . -type f -exec sed -i -e '$a\' {} \; -print 

Spiegazione: trovare tutti i file (-type f), eseguire sed, modificare i file in-place (-i), data il seguente (-e) script/espressione, che corrisponde alla fine del file ($), ed esegue l'azione "aggiungi" (a\), ma in realtà non specifica alcun testo da aggiungere (nulla dopo lo \) che sta andando per aggiungere una nuova riga alla fine del file, ma solo se manca. Stampa tutti i file trovati (fissi o meno), che probabilmente non è necessario.

L'avvertenza principale è che le funzionalità di sed variano da una piattaforma all'altra, quindi -i e -e possono o non possono essere supportate/le stesse; per esempio. le vecchie probabilità Unix o MacOS possono richiedere una sintassi leggermente diversa.

Problemi correlati