Wie sucht man unter Linux mit grep nach Dateien, die dos line endings (CRLF) enthalten?


125

Ich möchte unter Linux nach Dateien suchen, die Dos-Line-Endungen mit grep enthalten. Etwas wie das:

grep -IUr --color '\r\n' .

Das Obige scheint für wörtlich zu passen, rnwas nicht erwünscht ist.

Die Ausgabe davon wird durch xargs in todos geleitet, um crlf in lf wie folgt umzuwandeln

grep -IUrl --color '^M' . | xargs -ifile fromdos 'file'

2
Haben Sie dos2unix ausprobiert ? Zeilenenden werden automatisch behoben.
sblundy

Ich bin mir nicht ganz sicher, aber es gibt einen Unterschied zwischen dem Zitieren des Musters in 'und ". Afaik in Mustern, die in' den Escape-Sequenzen enthalten sind, werden als richtige Zeichenfolge interpretiert, sodass '\ r' gleichbedeutend mit" \\ r "und" ist. \ r "hat kein Äquivalent (zumindest in dieser Notation) zu '.
Anticom

Anticom: In diesem Fall haben Sie Recht, dass der Unterschied zwischen 'und' irrelevant ist. Im Allgemeinen unterscheiden sie sich jedoch darin, dass 'umgebene Zeichenfolgen schwach und "stark zitiert sind. Das größte, was ich ausnutzen kann, ist, dass $ -Erweiterungen oder `` nicht in schwach zitierten Zeichenfolgen expandieren. Weitere Informationen finden Sie unter Bash-Hacker zum Zitieren .
bschlueter

4
Am einfachsten ist es, modern dos2unixmit -icSchalter zu verwenden. Nach LF-Dateien können Sie mit unix2dos suchen -ic. Dateien werden nicht geändert. Nur melden.
Gavenkoa

3
Da dies eine Top-Antwort auf alle Fragen zu Windows-Zeilenenden / Wagenrückläufen unter Linux ist, ist es meiner Meinung nach erwähnenswert, dass Sie sie mit dem Befehl im Terminal sehen können cat -v somefile.txt. Sie erscheinen als^M
user5359531

Antworten:


121

Verwenden Sie Ctrl+ V, Ctrl+ M, um ein wörtliches Carriage Return-Zeichen in Ihre Grep-Zeichenfolge einzugeben. So:

grep -IUr --color "^M"

wird funktionieren - wenn ^Mes eine wörtliche CR gibt, die Sie wie vorgeschlagen eingegeben haben.

Wenn Sie die Liste der Dateien möchten, möchten Sie auch die -lOption hinzufügen .

Erläuterung

  • -I Binärdateien ignorieren
  • -Uverhindert, dass grep CR-Zeichen entfernt. Standardmäßig würde es dies tun, wenn es entscheidet, dass es sich um eine Textdatei handelt.
  • -r Lesen Sie alle Dateien unter jedem Verzeichnis rekursiv.

3
Als schneller Hack würde das funktionieren, aber ich denke, die menschliche Readbale-Lösung wäre: grep $ '\ r' / nur Bash-Shell / oder grepprintf '\r'
akostadinov

5
@akostadinov +1, aber Backticks wurden aus Ihrem Kommentar interpretiert;) Die zweite Option wäre mit anderen Worten grep $(printf '\r'). Aber für die meisten praktischen Anwendungen mit Bash würde ich bleiben $'\r'.
Jankes

3
Hinweis: Die Option -Uist nur für Windows (oder Cygwin) relevant, dort jedoch kritisch. Unter Windows funktioniert der Befehl ohne ihn nicht.
Sleske

3
Was ist der Sinn der Option -I? Nach dem Handbuch scheint es mir, dass Binärdateien als nicht übereinstimmend angesehen werden. Sollte die Kombination von -Iund -U(die den Binärtyp erzwingen) nicht dazu führen, dass alle Dateien als nicht übereinstimmend betrachtet werden?
Jānis Elmeris

3
Sie erwähnen das '-l'-Flag als Add-On-Option, aber ich denke, es sollte in der primären Antwort enthalten sein, da die Frage im Wesentlichen nach einer Liste von Dateien fragt. Dies führt auch zu einer schnelleren Suche.
arr_sea

166

grep ist wahrscheinlich nicht das Werkzeug, das Sie dafür wollen. Es wird eine Zeile für jede übereinstimmende Zeile in jeder Datei gedruckt. Wenn Sie beispielsweise nicht zehnmal todos für eine Datei mit 10 Zeilen ausführen möchten, ist grep nicht der beste Weg, dies zu tun. Wenn Sie find verwenden, um eine Datei für jede Datei im Baum auszuführen, und diese dann für "CRLF" durchgehen, erhalten Sie eine Ausgabezeile für jede Datei mit Zeilenenden im Dos-Stil:

find . -not -type d -exec file "{}" ";" | grep CRLF

bekommst du so etwas wie:

./1/dos1.txt: ASCII text, with CRLF line terminators
./2/dos2.txt: ASCII text, with CRLF line terminators
./dos.txt: ASCII text, with CRLF line terminators

Ich hatte das schon geknackt, aber trotzdem danke. grep -IUrl --color '^M' . | xargs -ifile fromdos 'file'
Tim Abell

5
Die Option -l für grep weist an, nur Dateien (einmal) aufzulisten, anstatt die Übereinstimmungen in jeder Datei aufzulisten.
pjz

7
Keine gute Lösung, um von diesem (undokumentierten, auf den menschlichen Konsum ausgerichteten) Verhalten des fileProgramms abzuhängen . Das ist sehr zerbrechlich. Zum Beispiel (nur ein Beispiel): Es funktioniert nicht mit XML-Dateien, fileBerichten XML document textunabhängig vom Newlines-Typ.
Leonbloy

1
@leonbloy, die Option scheint -m /dev/nullauf meinem find (GNU findutils) 4.4.2(Ubuntu 12.04) ein Kleinbuchstabe zu sein .
EarlCrapstone

7
Diese Antwort gefällt mir am besten. Ich habe es einfach getanfind . -type f | xargs file | grep CRLF
Brianz

58

11
Vielen Dank! Zur Verdeutlichung derjenigen, die danach kommen, heißt es im Bash-Handbuch: "Wörter der Form $ 'string' werden speziell behandelt. Das Wort wird zu string erweitert, wobei Zeichen mit Backslash-Escapezeichen gemäß ANSI C-Standard ersetzt werden." (Siehe auch diese Liste der unterstützten Codes )
Sean Gugler

5
Ist das Bash-spezifisch? Es sollte beachtet werden, wenn es ist.
cubuspl42

Für Git mit schlechtem Autocrlf würde ich verwenden: grep -IUlrZ $ '\ r' | xargs -0 sed -zbi 's / \ r // g'
Buzard

16

Wenn Ihre Version von grep die Option -P (--perl-regexp) unterstützt , dann

grep -lUP '\r$'

könnte verwendet werden.


8
# list files containing dos line endings (CRLF)

cr="$(printf "\r")"    # alternative to ctrl-V ctrl-M

grep -Ilsr "${cr}$" . 

grep -Ilsr $'\r$' .   # yet another & even shorter alternative

3

Die Abfrage war Suche ... Ich habe ein ähnliches Problem ... jemand hat gemischte Zeilenenden in die Versionskontrolle eingegeben, daher haben wir jetzt eine Reihe von Dateien mit 0x0d 0x0d 0x0aZeilenenden. Beachten Sie, dass

grep -P '\x0d\x0a'

findet alle Zeilen, während

grep -P '\x0d\x0d\x0a'

und

grep -P '\x0d\x0d'

findet keine Zeilen, so dass in grep möglicherweise etwas "anderes" vor sich geht, wenn es um Zeilenendmuster geht ... leider für mich!


3

Sie können den Dateibefehl unter Unix verwenden. Sie erhalten die Zeichencodierung der Datei zusammen mit Zeilenabschlüssen.

$ file myfile
myfile: ISO-8859 text, with CRLF line terminators
$ file myfile | grep -ow CRLF
CRLF  

1

Wenn Ihr minimalistisches Unix wie ich keine Feinheiten wie den Befehl file enthält und Backslashes in Ihren grep- Ausdrücken einfach nicht zusammenarbeiten, versuchen Sie Folgendes :

$ for file in `find . -type f` ; do
> dump $file | cut -c9-50 | egrep -m1 -q ' 0d| 0d'
> if [ $? -eq 0 ] ; then echo $file ; fi
> done

Zu den Änderungen, die Sie möglicherweise an den oben genannten Änderungen vornehmen möchten, gehören:

  • Optimieren Sie den Befehl find , um nur die Dateien zu finden, die Sie scannen möchten
  • Ändern Sie den Befehl dump in od oder ein anderes Dienstprogramm zum Speichern von Dateien
  • Vergewissern Sie sich, dass der Befehl cut sowohl ein führendes als auch ein nachfolgendes Leerzeichen sowie nur das vom Dump- Dienstprogramm ausgegebene Hexadezimalzeichen enthält
  • Begrenzen Sie die Dump- Ausgabe aus Effizienzgründen auf die ersten 1000 Zeichen

Zum Beispiel könnte so etwas für Sie funktionieren, wenn Sie od anstelle von dump verwenden :

 od -t x2 -N 1000 $file | cut -c8- | egrep -m1 -q ' 0d| 0d|0d$'

1

dos2unix verfügt über eine Dateiinformationsoption, mit der die zu konvertierenden Dateien angezeigt werden können:

dos2unix -ic /path/to/file

Um das zu tun rekursiv können Sie mit bash‚s - globstarOption, die für den aktuell Shell aktiviert mit shopt -s globstar:

dos2unix -ic **      # all files recursively
dos2unix -ic **/file # files called “file” recursively

Alternativ können Sie dafür verwenden find:

find -exec dos2unix -ic {} +            # all files recursively
find -name file -exec dos2unix -ic {} + # files called “file” recursively
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.