2011-01-07 4 views
17

Wie kann ich normalen Text (.txt) Dateinamen auflisten, die nicht mit einem Zeilenumbruch enden?Wie liste ich Dateien auf, die nicht mit einem Zeilenumbruch enden?

z.B .: Liste (Ausgabe) Dieser Dateiname:

$ cat a.txt 
asdfasdlsad4randomcharsf 
asdfasdfaasdf43randomcharssdf 
$ 

und nicht Liste (Output) Dieser Dateiname:

$ cat b.txt 
asdfasdlsad4randomcharsf 
asdfasdfaasdf43randomcharssdf 

$ 
+0

Suchen Sie nur nach einer breiten Anzeige von Dateien aus einem Ordner nach unten? Ihre Frage ist im obigen Beispiel nicht sehr klar. – James

+2

Was bedeutet "normales txt"? Sprechen Sie über Dateien, die mit einer * leeren * Zeile (\ n \ n) enden oder nur Dateien, die mit einem Zeilenumbruch enden? Sie können 'od -c filename' verwenden, um eine eindeutige Darstellung der Datei zu drucken. – jfs

+1

Nur um zu betonen: Newline ist * nicht * das gleiche wie * leere * Zeile. Ein Newline ist ein einzelnes Zeichen - es grenzt ab, was wir als "Zeilen" sehen. Eine leere Zeile ist einfach eine "Zeile" ohne Zeichen, typischerweise zwei aufeinanderfolgende Zeilenwechselzeichen mit nichts dazwischen oder die erste Zeile in einer Datei, die mit einem Zeilenumbruch beginnt. Einige Leute rufen auch Zeilen auf, die nur aus Leerzeilen bestehen, und reservieren den Begriff "Leerzeile" für zwei aufeinanderfolgende Zeilenwechselzeichen. Sie sollten sich darüber klar sein, was Sie wollen. – jw013

Antwort

2

Dies ist kludgy; jemand kann es sicherlich besser machen:

for f in `find . -name '*.txt' -type f`; do 
    if test `tail -c 1 "$f" | od -c | head -n 1 | tail -c 3` != \\n; then 
     echo $f; 
    fi 
done 

N.B. Dies beantwortet die Frage im Titel, die sich von der Frage im Textkörper unterscheidet (der nach Dateien sucht, die mit \ n \ n enden, denke ich).

2

Diese den Trick tun sollten:

#!/bin/bash 

for file in `find $1 -type f -name "*.txt"`; 
do 
     nlines=`tail -n 1 $file | grep '^$' | wc -l` 
     if [ $nlines -eq 1 ] 
       then echo $file 
     fi 
done; 

es auf diese Weise aufrufen: ./script dir

Z.B. ./script /home/user/Documents/ -> listet alle Textdateien in /home/user/Documents auf, die mit \n enden.

+0

Die erste Verbesserung besteht darin, 'IFS = $ '\ n'' vorher zu setzen. Es ermöglicht, Dateien mit Leerzeichen zu behandeln. Die zweite Verbesserung besteht darin, '$ nlines -eq 1' durch' $ nlines -eq 0' zu ersetzen, da der Autor "Dateinamen benötigt, die ** nicht mit einem Newline endet **". –

7

Geben Sie diesen einen Versuch:

find -type f -exec sh -c '[ -z "$(sed -n "\$p" "$1")" ]' _ {} \; -print 

Es wird Dateinamen von Dateien drucken, die mit einer Leerzeile beenden. Um Dateien zu drucken, die nicht in einer leeren Zeile enden, ändern Sie die -z in -n.

+1

Die Antworten, die 'for ... find ... do' verwenden, schlagen fehl, wenn Dateinamen Leerzeichen enthalten. –

+1

Sie sind richtig über 'for .. find..' http://mywiki.wooledge.org/BashPitfalls#for_i_in_.24.28ls_.2A.mp3.29 – jfs

+1

Ausgezeichnete Lösung. Empfehlen Sie, dass Sie nicht als Teil des 'sh'-Skripts ein Echo geben und fügen Sie am Ende des find-Befehls' -print' hinzu. Dann kann der "Ausdruck" zu dem geändert werden, was benötigt wird (z. B. "-print0"). – squid314

1

Eine weitere Option:

$ find . -name "*.txt" -print0 | xargs -0I {} bash -c '[ -z "$(tail -n 1 {})" ] && echo {}' 
+0

Vielen Dank, dies ist das einzige Beispiel in diesem Thread, das tatsächlich funktioniert (auf OSX) –

+0

... eigentlich scheint dies nicht die richtigen Dateien zu finden –

0

Da Ihre Frage das Perl-Tag hat, werde ich eine Antwort hinterlassen, die sie verwendet:

find . -type f -name '*.txt' -exec perl check.pl {} + 

wo check.pl ist die folgende:

#!/bin/perl 

use strict; 
use warnings; 

foreach (@ARGV) { 
    open(FILE, $_); 

    seek(FILE, -2, 2); 

    my $c; 

    read(FILE,$c,1); 
    if ($c ne "\n") { 
     print "$_\n"; 
    } 
    close(FILE); 
} 

Dieses Perl-Skript nur öffnen, eins pro Zeit, die Dateien als Parameter übergeben und nur das vorletzte Zeichen lesen; Wenn es sich nicht um ein Zeilenumbruchzeichen handelt, wird nur der Dateiname ausgegeben, andernfalls wird nichts ausgeführt.

+0

Was ist, wenn das letzte Zeichen kein Zeilenumbruch ist (natürlich es ist keine gültige Textdatei)? –

17

Verwenden pcregrep, ein Perl Compatible Regular Expressions-Version von grep, die ein mehrzeiliges Modus mit -M-Flag unterstützt, die verwendet werden können, entsprechen (oder passen nicht zusammen), wenn die letzte Zeile eine neue Zeile hatte:

pcregrep -LMr '\n$' . 

Im obigen Beispiel sagen wir, dass rekursiv (-r) im aktuellen Verzeichnis (.) nicht übereinstimmende Dateien (-L) unserer multiline (-M) regex suchen, die nach einem Zeilenende am Ende einer Datei ('\n$')

sucht

Ändern -L bis -l würde die Dateien auflisten, die do Zeilenumbrüche in ihnen haben.

+0

Ich sollte darauf hinweisen, dass die Antwort von @ dennis-williamson auch für Dateien fehlschlägt, die Leerzeichen in ihnen hat. Zumindest hat es für mich getan. –

+0

Ich habe in meiner Antwort eine Reihe von fehlenden Anführungszeichen hinzugefügt, die sich um dieses Problem kümmern sollten. –

+1

Nur ein Hinweis für zukünftige Leser: Dieser Befehl pcregrep ist korrekt für Dateien, die * keine * leere Zeilen enthalten. Gegenbeispiel: 'printf 'a \ n \ nb" | pcregrep -M '\ n $' -' druckt 'a' (und somit wird beim Ausführen mit' -L' nichts gedruckt). – maverickwoo

14

Ok bin ich dran, gebe ich ihm einen Versuch:

find -type f -print0 | xargs -0 -L1 bash -c 'test "$(tail -c 1 "$0")" && echo "No new line at end of $0"' 
1

Dieses Beispiel funktioniert für mich auf OSX (viele der oben genannten Lösungen nicht tat)

for file in `find . -name "*.java"` 
do 
    result=`od -An -tc -j $(($(ls -l $file | awk '{print $5}') - 1)) $file` 
    last_char=`echo $result | sed 's/ *//'` 
    if [ "$last_char" != "\n" ] 
    then 
    #echo "Last char is .$last_char." 
    echo $file 
    fi 
done 
3

Wenn Sie verwenden ack‘(http://beyondgrep.com) als Alternative zu grep, führen Sie nur das:

ack -v '\n$' 

Es sucht eigentlich alle Linien das passt (-v) nicht an einen Zeilenumbruch am Ende der Zeile.

+1

Einfache, einfache Lösung. Fügen Sie '-l' hinzu, um nur die übereinstimmenden Dateien und nicht die Zeile zu erhalten. – stu42j

1

Die meisten Lösungen auf dieser Seite funktionieren nicht für mich (FreeBSD 10.3 amd64). Ian Wills OSX Lösung funktioniert fast immer, aber ist ziemlich schwer zu folgen: - (

Es gibt eine einfache Lösung, die fast immer zu arbeiten: (wenn $ f die Datei):

sed -i '' -e '$ a \' "$ f"

es ist ein großes Problem mit der sed Lösung. es gibt Ihnen nie die Gelegenheit, einfach zu überprüfen (und nicht eine neue Zeile anhängen)

Beide oben genannten Lösungen für DOS-Dateien fehlschlagen.Ich denke, die meisten portable/skriptfähige Lösung ist wahrscheinlich wahrscheinlich die einfachste, die ich selbst entwickelt habe: -)

Hier ist das elementare SH-Skript, das Datei/Unix2dos/Tail kombiniert. In Produktion, werden Sie wahrscheinlich benötigen "$ f" in Anführungszeichen zu verwenden und Schwanz Ausgabe (eingebettet in den Shell-Variable mit dem Namen letzten) als \ "$ f \"

if file $f | grep 'ASCII text' > /dev/null; then 
    if file $f | grep 'CRLF' > /dev/null; then 
     type unix2dos > /dev/null || exit 1 
     dos2unix $f 
     last="`tail -c1 $f`" 
     [ -n "$last" ] && echo >> $f 
     unix2dos $f 
    else 
     last="`tail -c1 $f`" 
     [ -n "$last" ] && echo >> $f 
    fi 
fi 

Hope this jemand hilft holen.

Verwandte Themen