Come si cercano file contenenti terminazioni di riga dos (CRLF) con grep su Linux?


126

Voglio cercare file contenenti terminazioni di riga dos con grep su Linux. Qualcosa come questo:

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

Quanto sopra sembra corrispondere al letterale rnche non è ciò che si desidera.

L'output di questo verrà convogliato attraverso xargs in todos per convertire crlf in lf in questo modo

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

2
Hai provato dos2unix ? Corregge automaticamente le terminazioni di riga.
sblundy

Non sono del tutto sicuro, ma c'è una differenza tra il citare il modello all'interno di 'e ". Afaik nei modelli racchiusi in' le sequenze di escape sono interpretate come una stringa corretta, quindi '\ r' sarebbe equivalente a" \\ r "e" \ r "non ha equivalenti (almeno in quella notazione) con '.
Anticom

Anticom: Hai ragione in questo caso che la differenza tra "e" è irrilevante; tuttavia, generalmente sono distinte in quanto "le stringhe racchiuse sono virgolette deboli e" sono citate forti. La cosa più importante di cui traggo vantaggio è che $ espansioni o `` non si espandono in stringhe tra virgolette deboli. Vedi bash-hacker sulle citazioni per ulteriori informazioni.
bschlueter

4
Il modo più semplice è usare moderno dos2unixcon -icinterruttore. Per i file LF puoi cercare con unix2dos -ic. Non modifica i file. Solo rapporto.
gavenkoa

3
poiché questa è una risposta eccellente per qualsiasi domanda riguardante le terminazioni di riga di Windows / i ritorni a capo su Linux, penso che valga la pena notare che puoi vederli nel terminale con il comando cat -v somefile.txt; si presentano come^M
utente5359531

Risposte:


121

Usa Ctrl+ V, Ctrl+ Mper inserire un carattere di ritorno a capo letterale nella tua stringa grep. Così:

grep -IUr --color "^M"

funzionerà - se ^Mc'è un CR letterale che inserisci come ho suggerito.

Se desideri l'elenco dei file, aggiungi anche l' -lopzione.

Spiegazione

  • -I ignora i file binari
  • -Uimpedisce a grep di rimuovere i caratteri CR. Per impostazione predefinita, lo farebbe se decide che è un file di testo.
  • -r legge ricorsivamente tutti i file in ogni directory.

3
Come un trucco rapido che funzionerebbe, ma penso che la soluzione di readbale umana sarebbe: grep $ '\ r' / bash shell only / o grepprintf '\r'
akostadinov

5
@akostadinov +1, ma backticks ma ho interpretato dal vostro commento;) La seconda opzione sarebbe, in altre parole, essere grep $(printf '\r'). Ma per la maggior parte degli usi pratici che coinvolgono bash, vorrei restare $'\r'.
jankes

3
Nota: l'opzione -Uè rilevante solo per Windows (o cygwin), ma è fondamentale. Su Windows, il comando non funzionerà senza di esso.
sleske

3
Qual è lo scopo dell'opzione -I? Dal manuale, mi sembra che i file binari siano considerati non corrispondenti. La combinazione di -Ie -U(che impone il tipo binario) non dovrebbe comportare che tutti i file vengano considerati non corrispondenti?
Jānis Elmeris

3
Citi il ​​flag "-l" come opzione aggiuntiva, ma penso che dovrebbe essere incluso nella risposta principale perché la domanda richiede essenzialmente un elenco di file. Inoltre, risulta in una ricerca più veloce.
arr_sea

168

grep probabilmente non è lo strumento che desideri per questo. Stamperà una riga per ogni riga corrispondente in ogni file. A meno che tu non voglia, ad esempio, eseguire todos 10 volte su un file di 10 righe, grep non è il modo migliore per farlo. Usando find per eseguire il file su ogni file nell'albero e poi sfogliandolo per "CRLF" otterrai una riga di output per ogni file che ha terminazioni di riga in stile dos:

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

ti darà qualcosa come:

./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

L'avevo già risolto, ma grazie comunque. grep -IUrl --color '^M' . | xargs -ifile fromdos 'file'
Tim Abell

5
L'opzione -l di grep gli dice di elencare solo i file (una volta) invece di elencare le corrispondenze in ogni file.
pjz

8
Non è una buona soluzione, dipendere da quel comportamento (non documentato, orientato al consumo umano) del fileprogramma. Questo è molto fragile. Per (solo un) esempio: non funziona con i file XML, i filerapporti XML document textindipendentemente dal tipo di nuova riga.
Leonbloy

1
@leonbloy, l'opzione sembra essere minuscola -m /dev/nullsul mio find (GNU findutils) 4.4.2(Ubuntu 12.04).
EarlCrapstone

8
Mi piace questa risposta la migliore. Ho semplicemente fattofind . -type f | xargs file | grep CRLF
brianz

58
grep -IUlr $'\r'

spiegahell.com - grep -IUlr


11
Grazie! Per la chiarezza di coloro che vengono dopo, il manuale di bash dice "Le parole nella forma $ 'stringa' sono trattate in modo speciale. La parola si espande in stringa, con caratteri di escape backslash sostituiti come specificato dallo standard ANSI C." (vedi anche questo elenco di codici supportati )
Sean Gugler

5
Quindi questo è specifico di bash? Va notato se lo è.
cubuspl42

per git con mal autocrlf, userei: grep -IUlrZ $ '\ r' | xargs -0 sed -zbi 's / \ r // g'
buzard

16

Se la tua versione di grep supporta l' opzione -P (--perl-regexp) , allora

grep -lUP '\r$'

potrebbe essere usato.


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

La query era ricerca ... Ho un problema simile ... qualcuno ha inviato terminazioni di riga miste nel controllo della versione, quindi ora abbiamo un mucchio di file con 0x0d 0x0d 0x0aterminazioni di riga. Nota che

grep -P '\x0d\x0a'

trova tutte le righe, mentre

grep -P '\x0d\x0d\x0a'

e

grep -P '\x0d\x0d'

non trova linee quindi potrebbe esserci qualcos'altro in corso all'interno di grep quando si tratta di schemi di fine linea ... sfortunatamente per me!


3

Puoi usare il comando file in unix. Ti dà la codifica dei caratteri del file insieme ai terminatori di riga.

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

1

Se, come me, il tuo unix minimalista non include sottigliezze come il comando file e le barre rovesciate nelle espressioni grep semplicemente non cooperano, prova questo:

$ 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

Le modifiche che potresti voler apportare a quanto sopra includono:

  • modificare il comando find per individuare solo i file che si desidera esaminare
  • cambia il comando dump in od o qualsiasi altra utility di dump del file che hai
  • confermare che il comando di taglio include sia uno spazio iniziale che uno finale, nonché solo l'output di caratteri esadecimali dall'utilità di dump
  • limitare l' output del dump ai primi 1000 caratteri circa per l'efficienza

Ad esempio, qualcosa del genere potrebbe funzionare per te usando od invece di dump :

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

1

dos2unix ha un'opzione di informazioni sui file che può essere utilizzata per mostrare i file che verrebbero convertiti:

dos2unix -ic /path/to/file

Per farlo in modo ricorsivo puoi usare bashl' globstaropzione s , che per la shell corrente è abilitata con shopt -s globstar:

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

In alternativa puoi usare findper quello:

find -exec dos2unix -ic {} +            # all files recursively
find -name file -exec dos2unix -ic {} + # files called “file” recursively
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.