Ich habe Dateien in Unterverzeichnissen des aktuellen Verzeichnisses, die am Ende möglicherweise neue Zeilen enthalten oder nicht. Wie finde ich Dateien, die am Ende keinen Zeilenumbruch haben?
Ich habe das versucht:
find . -name '*.styl' | while read file; do
awk 'END{print}' $file | grep -E '^$' > /dev/null || echo $file;
done
aber es funktioniert nicht. awk 'END{print}' $file
druckt die Zeile vor einer leeren neuen Zeile, genau wie tail -n 1 $file
.
awk 'END{print}' $file
: Dies ignoriert den Inhalt von $ file vollständig und fügt nach Abschluss des Parsens aller in "$ file" enthaltenen Dateien eine neue Zeile hinzu. Da es das einzige ist, was der Befehl awk druckt, kann er durchprintf '\n'
Folgendes ersetzt werden (ohne Mentino von $ file überhaupt) und dasselbe tun. Ich denke, das ist NICHT das, was Sie angestrebt haben (dh: die letzte Zeile der Datei drucken?)c
und FreeBSD auch, aber ich hatte nicht bemerkt, dass es als implementierungsabhängig dokumentiert ist: gnu.org/software/gawk/manual/… . So kommt es aber nicht immer vor.Antworten:
Um zu klären, ist die LF (aka
\n
oder Neues - Zeile) Zeichen sind die Zeilentrennzeichen , es ist nicht das Linientrenner. Eine Zeile wird erst beendet, wenn sie durch ein Zeilenumbruchzeichen abgeschlossen ist. Eine Datei, die nur enthält,a\nb
ist keine gültige Textdatei, da sie Zeichen nach der letzten Zeile enthält. Gleiches gilt für eine Datei, die nur enthälta
. Eine Datei, die enthält,a\n
enthält eine nicht leere Zeile.Eine Datei, die mit mindestens einer Leerzeile endet, endet mit zwei Zeilenumbrüchen oder enthält ein einzelnes Zeilenumbruchzeichen.
Wenn:
Gibt
\n
oder aus\n \n
, dann enthält die Datei mindestens eine nachgestellte Leerzeile. Wenn es nichts ausgibt, ist das eine leere Datei. Wenn es ausgegeben wird<anything-but-\0> \n
, endet es in einer nicht leeren Zeile. Alles andere ist keine Textdatei.Um dies zu verwenden, um Dateien zu finden, die in einer leeren Zeile enden, ist dies insofern effizient (insbesondere bei großen Dateien), als nur die letzten zwei Bytes der Dateien gelesen werden. Zunächst ist die Ausgabe jedoch nicht einfach programmgesteuert zu analysieren, insbesondere wenn man bedenkt, dass dies der Fall ist nicht konsistent von einer Implementierung
od
zur nächsten, und wir müssten einetail
und eineod
pro Datei ausführen .(um Dateien zu finden, die in einer leeren Zeile enden) würde so wenig Befehle wie möglich ausführen, aber das Lesen des gesamten Inhalts aller Dateien bedeuten.
Idealerweise benötigen Sie eine Shell, die das Ende einer Datei selbst lesen kann.
Mit
zsh
:quelle
are_textfiles () { nontext=0; rem="return 0 if all args are files with terminating newline, or n [=number of non-textfiles]" ; for f in "$@" ; do [ -f "$f" ] && { tail -c 1 "$f" | od -An -vtc | grep "\\n" ;} >/dev/null 2>&1 || ((nontext++)) ; done ; return $nontext ; }
. Verwendung als:if ( are_textfiles this that otherthing ) ; then echo all are text files ; else echo "are_textfiles returned : $?" ; fi
Mit
gnu sed
und einer Shell wiezsh
(oderbash
mitshopt -s globstar
):Dadurch wird überprüft, ob die letzte Zeile jeder Datei nicht leer ist. In diesem Fall wird der Dateiname gedruckt.
Wenn Sie das Gegenteil wollen (Dateinamen drucken , wenn die letzte Zeile leer ist) ersetzen Sie einfach
/./
mit/^$/
quelle
-s
in Aktion gesehen. Danke GNU!Eine korrekt abgeschlossene Textdatei mit einer leeren letzten Zeile endet in zwei
\n
.Dann erwarten wir, dass
tail -c2
das gleich sein muss$'\n\n'
.Befehlserweiterungen entfernen leider nachfolgende neue Zeilen. Wir müssen ein bisschen optimieren.
Wir könnten sogar ein wenig erweitern, um zu überprüfen, welche Dateien keine nachfolgende neue Zeile haben:
Beachten Sie, dass die neue Zeile bei Bedarf geändert werden kann
$'\r\n
.Wechseln Sie
tail -c2
in diesem Fall auch zutail -c4
.quelle
quelle
cat $file 2>&1 /dev/null
oder wenn dies nur Bash ist ,cat $file &> /dev/null
.$file
$(commands ...)
`backticks`