2010-07-16 4 views
9

Ich habe eine große Anzahl von Quelldateien, die alle am Ende einen Zeilenumbruch haben.Wie man "No newline am Ende der Datei" Warnung für viele Dateien beheben?

Wie füge ich automatisch eine neue Zeile am Ende von jedem von ihnen hinzu?

Einige haben möglicherweise bereits eine neue Zeile, daher sollte sie nur bei Bedarf hinzugefügt werden.

Ich bin wahrscheinlich nicht auf der Suche nach Code, per se, aber nur etwas, was ich in Terminal ausführen kann, um die notwendigen Zeilenumbrüche (oder eine Art von Programmierung oder Entwicklungstool) hinzuzufügen.

Antwort

3

Konvertiert Normans Antwort auf einen geteilten One-Liner für Bequemlichkeit.

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

* Ersetzen Sie mit dem, was Dateimuster Sie wollen, zB *.c

und ein anderes zu Ihnen sagen, welche Dateien defekt sind:

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

Keine der Lösungen funktioniert für mich –

+1

Wenn Sie wollen, dass es rekursiv geht, können Sie '*' vertauschen mit '$ (find. -type f)' oder '$ (find -type f -name )' – durron597

7

Wenn Sie Zugriff auf Unix-Tools haben, können Sie diff laufen, um herauszufinden, welche Dateien ein Newline fehlt und dann hängen Sie es:

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

Ich bin auf diff verlassen, um die Nachricht mit einem \ zu erzeugen, in die erste Spalte, tail mir die letzte Zeile des diff ‚s Ausgangs zu geben, und grep mir zu sagen, ob die letzte Zeile ist die Nachricht, die ich suche. Wenn das alles funktioniert, dann erzeugt die echo eine neue Zeile und die >> hängt es an die Datei "$i" an. Die Anführungszeichen um "$i" stellen sicher, dass die Dinge funktionieren, wenn der Dateiname Leerzeichen enthält.

+2

Nicht schlecht, aber grep gibt eine lokalisierte Nachricht zurück, wie "\ Brak znaku nueuej linii (usw.)". Außerdem gibt das diff die ganze Datei aus. Ich würde 'tail -1 $ f | grep '\ n'' für den Zustand (funktioniert auf meiner Box). –

+0

@TomaszGandor: 'Tail -1 Dateiname | grep '\ n' scheint immer ein falsches Ergebnis auf meinem Mac zurückzugeben, unabhängig davon, ob es einen nachgestellten Zeilenumbruch gibt oder nicht. – Gino

2

OK, nachdem in den Kommentaren beschweren, gibt es meine bessere Lösung. Erstens wollen Sie wissen, welche Dateien fehlen Zeilenumbrüche:

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

nicht super schnell (ein paar Prozesse für jede Datei aufrufen), aber es ist in Ordnung für den praktischen Gebrauch.

Nun, wenn Sie es haben, können Sie auch das Newline hinzufügen, mit einem anderen -exec:

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

Mögliche gotchas:

  • wenn Dateinamen schlecht sind, z.B. Sie haben Leerzeichen, möglicherweise benötigen Sie tail -1 \"{}\". Oder findet es richtig?

  • möchten Sie vielleicht weitere Filter zu finden, wie -name \*py oder dergleichen.

  • über mögliche DOS/Unix Newlines Chaos vor der Verwendung denken (das zuerst beheben).

EDIT:

Wenn Sie die Ausgabe dieser Befehle nicht mögen (einige hex Echo), fügen -q 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

Das ist * riesiger * Overkill. – tripleee

0

Aufgrund Antwort Lokalisierung Tim und Norman befehlen Soll verbessert werden, indem das Präfix "LANG = C" verwendet wird, damit das Muster "Kein Zeilenumbruch" mit jedem System mit allen regionalen Parametern übereinstimmt

Dies stellt eine leere Endezeile sicher auf jede Datei auf der Kommandozeile dieses Skript setzen:

#!/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 

Und dieses Skript erkennt Dateien es fehlt:

#!/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

Try Ex-Weg:

ex -s +"bufdo wq" *.c 

Und rekursiv (mit a new globbing option aktiviert):

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

Dies entspricht vi -es. Ändern Sie *.c zur Erweiterung Ihres Interesses.

Die ex/vi würde automatisch Newline an Save anhängen, wenn es nicht vorhanden ist.

0

Nach dem Finden des Tools diesen Job ohne Glück. Ich beschließe, meine schreiben eigene

Das ist mein Python-Skript, dass Job

Es nur zu tun anhängen (\ r \ n) Datei nicht enthält (\ n) am Ende der Datei

https://github.com/tranhuanltv/append_newline

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

Make Pull Requests, wenn Sie

+0

Das ist sehr fraglich - die Suche nach -1 von END ist in Ordnung, aber Sie könnten Unix und DOS-Zeilenumbrüche auf diese Weise leicht mischen ... –

0

will ich bin überrascht, niemand hat erwähnt, dass viele einfache Textverarbeitungstools wie Awk einen Newline als Nebeneffekt hinzufügen. Hier ist eine einfache Schleife, die eine Datei nur dann überschreibt, wenn eine neue Zeile hinzugefügt wurde.

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

(Die temporäre Datei ist offensichtlich ein bisschen eine Warze.)

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 

Es gibt mehrere Schritte, die hier beteiligt: ​​

  1. Recursively Dateien finden
  2. erkennen, welche Dateien ein nachlauf neue Linie
  3. Schleife über jeweils fehlt diese Dateien
  4. Fügen Sie die Zeilenumbrüche

Schritt 1 wird traditionell mit find (in Anlehnung an die Unix-Tradition „jedes Werkzeugs eine Sache zu tun und es gut tun“) gemacht, aber da pcregrep builtin Unterstützung hat, ich bin bequem es zu benutzen. Ich achte darauf, nicht mit dem .git-Ordner herumzualbern.

Schritt 2 ist mit einem mehrzeiligen regelmäßig getan Ausdruck entsprechenden Dateien, die eine abschließende Newline tun und Drucken, die Namen der Dateien, die nicht Spiel.

Schritt 3 ist mit einer while/read-Schleife statt einer for/in gemacht, da letztere für Dateinamen mit Leerzeichen und für extrem lange Listen von Dateien fehlschlägt.

Schritt 4 ist ein einfaches Echo, das dem Ansatz von @ norman-ramsey folgt.

h/t @ Anthony-Busch https://stackoverflow.com/a/20687956/577438 für den Vorschlag pcregrep.

1

Ich verwende find statt for f in * wie es rekursiv ist und die Frage war, über „große Anzahl von Quelldateien“.

Ich benutze while read anstelle von find -exec oder xargs aus Leistungsgründen spart es Laichen Shell-Prozess jedes Mal.

Ich nutze die Tatsache, dass der Backtick-Operator die Ausgabe des Befehls "mit irgendwelchen abschließenden Zeilenumbrüchen gelöscht" man bash zurückgibt, so dass für korrekt beendete Dateien der Backtick leer ist und das Echo übersprungen wird.

Das find | read Paar wird auf Dateinamen fehlschlagen, die Zeilenumbrüche enthalten, aber es ist einfach, wenn erforderlich zu beheben:

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

0

Im Folgenden meine Bash-Skript-Lösung ist. Es prüft zuerst, ob die Datei eine Textdatei ist. Wenn es sich um eine Textdatei handelt, verwendet es tail und od (oktal dump), um zu sehen, ob das letzte Zeichen das Newline-Zeichen ist.Wenn dies nicht der Fall, dann fügt es eine neue Zeile echo:

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

Eine einfache Lösung für Dateien, die „fehlenden“ Newline am Ende der Datei wird einfach sed; Die folgende Updates der Datei "in-place" (die Option "-i" verwenden):

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

Erläuterung: alle Dateien findet (-type f), führte sed, die Dateien an Ort und Stelle ändern (-i), gegeben die folgende (-e) Skript/Ausdruck, die das Ende der Datei ($) entspricht, und führen Sie die Aktion "append" (a\), aber tatsächlich keinen Text anhängen (nichts nach der \), die geht um am Ende der Datei eine neue Zeile einzufügen, aber nur, wenn sie fehlt. Druckt alle gefundenen Dateien (repariert oder nicht), was wahrscheinlich unnötig ist.

Haupthindernis ist, dass sed Funktionen variieren über Plattformen, so -i und -e möglicherweise oder nicht unterstützt werden/gleich; z.B. Ältere Unix- oder MacOS-Kuriositäten erfordern möglicherweise eine etwas andere Syntax.