¿Cómo busca archivos que contengan terminaciones de dos líneas (CRLF) con grep en Linux?


126

Quiero buscar archivos que contengan terminaciones de dos líneas con grep en Linux. Algo como esto:

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

Lo anterior parece coincidir con literal, rnque no es lo que se desea.

La salida de esto se canalizará a través de xargs en todos para convertir crlf a lf de esta manera

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

2
¿Has probado dos2unix ? Repara los finales de línea automáticamente.
sblundy

No estoy muy seguro, pero hay una diferencia entre citar el patrón dentro de 'y ". Afaik en los patrones encerrados en' las secuencias de escape se interpretan como una cadena adecuada, por lo que '\ r' sería equivalente a" \\ r "y" \ r "no tiene equivalente (al menos en esa notación) con '.
Anticom

Anticom: Tiene razón en este caso de que la diferencia entre 'y "es irrelevante; sin embargo, generalmente son distintos ya que' las cadenas entre comillas son comillas débiles y 'son comillas fuertes. Lo más importante que aprovecho es que las expansiones de $ o `` no se expanden en cadenas débiles citadas. Ver bash-hackers en citas para más información.
bschlueter

44
La forma más fácil es usar moderno dos2unixcon -icinterruptor. Para archivos LF puede buscar con unix2dos -ic. No modifica los archivos. Solo informe.
gavenkoa

3
Dado que esta es una respuesta excelente para cualquier pregunta con respecto a los finales de línea de Windows / retornos de carro en Linux, creo que vale la pena señalar que puede verlos en la terminal con el comando cat -v somefile.txt; aparecen como^M
user5359531

Respuestas:


121

Use Ctrl+ V, Ctrl+ Mpara ingresar un carácter literal de retorno de carro en su cadena grep. Entonces:

grep -IUr --color "^M"

funcionará, si ^Mhay un CR literal que ingresas como sugerí.

Si desea la lista de archivos, también desea agregar la -lopción.

Explicación

  • -I ignorar archivos binarios
  • -Uevita que grep elimine los caracteres CR. Por defecto lo haría si decide que es un archivo de texto.
  • -r lea todos los archivos de cada directorio de forma recursiva.

3
Como un truco rápido que funcionaría, pero creo que la solución de readbale humana sería: grep $ '\ r' / bash shell only / o grepprintf '\r'
akostadinov

55
@akostadinov +1, pero los backticks se interpretaron a partir de su comentario;) La segunda opción sería, en otras palabras, ser grep $(printf '\r'). Pero para la mayoría de los usos prácticos que involucran bash, me quedaría con $'\r'.
enero

3
Nota: La opción -Usolo es relevante para Windows (o cygwin), pero es crítica allí. En Windows, el comando no funcionará sin él.
sleske

3
¿Cuál es el punto de opción -I? Según el manual, me parece que los archivos binarios se consideran no coincidentes. ¿No debería la combinación de -Iy -U(que impone el tipo binario) dar como resultado que todos los archivos se consideren no coincidentes?
Jānis Elmeris

3
Usted menciona el indicador '-l' como una opción de complemento, pero creo que debería incluirse en la respuesta principal porque la pregunta esencialmente pide una lista de archivos. Además, resulta en una búsqueda más rápida.
arr_sea

168

grep probablemente no es la herramienta que desea para esto. Imprimirá una línea para cada línea coincidente en cada archivo. A menos que desee, por ejemplo, ejecutar todos 10 veces en un archivo de 10 líneas, grep no es la mejor manera de hacerlo. Usando find para ejecutar el archivo en cada archivo en el árbol y luego pasando por eso para "CRLF" obtendrá una línea de salida para cada archivo que tiene terminaciones de línea de dos estilos:

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

te dará algo como:

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

Ya había resuelto esto, pero gracias de todos modos. grep -IUrl --color '^M' . | xargs -ifile fromdos 'file'
Tim Abell

55
La opción -l para grep le dice que solo enumere los archivos (una vez) en lugar de enumerar las coincidencias en cada archivo.
pjz

8
No es una buena solución, depender de ese comportamiento (indocumentado, orientado al consumo humano) del fileprograma. Esto es muy frágil. Por ejemplo (solo un): no funciona con archivos XML, los fileinformes , XML document textindependientemente del tipo de líneas nuevas.
leonbloy

1
@leonbloy, la opción parece estar en minúscula -m /dev/nullen mi find (GNU findutils) 4.4.2(Ubuntu 12.04).
EarlCrapstone

8
Me gusta esta respuesta la mejor. Simplemente lo hicefind . -type f | xargs file | grep CRLF
brianz

58
grep -IUlr $'\r'

explicahell.com - grep -IUlr


11
¡Gracias! Para mayor claridad de los que vienen después, el manual de bash dice "Las palabras de la forma $ 'string' se tratan especialmente. La palabra se expande a string, con los caracteres con barra invertida reemplazados según lo especificado por el estándar ANSI C". (vea también esta lista de códigos compatibles )
Sean Gugler

55
Entonces, ¿esto es específico de bash? Cabe señalar si es así.
cubuspl42

para git con mal autocrlf, usaría: grep -IUlrZ $ '\ r' | xargs -0 sed -zbi 's / \ r // g'
buzard

16

Si su versión de grep admite la opción -P (--perl-regexp) , entonces

grep -lUP '\r$'

puede ser usado.


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 consulta fue buscar ... Tengo un problema similar ... alguien envió terminaciones de línea mixtas en el control de versión, por lo que ahora tenemos un montón de archivos con 0x0d 0x0d 0x0aterminaciones de línea. Tenga en cuenta que

grep -P '\x0d\x0a'

encuentra todas las líneas, mientras que

grep -P '\x0d\x0d\x0a'

y

grep -P '\x0d\x0d'

no encuentra líneas, por lo que puede haber algo "más" dentro de grep cuando se trata de patrones de finalización de línea ... ¡desafortunadamente para mí!


3

Puede usar el comando de archivo en unix. Le proporciona la codificación de caracteres del archivo junto con los terminadores de línea.

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

1

Si, como yo, su unix minimalista no incluye detalles como el comando de archivo , y las barras invertidas en sus expresiones grep simplemente no cooperan, intente esto:

$ 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

Las modificaciones que puede hacer a lo anterior incluyen:

  • modifique el comando de búsqueda para localizar solo los archivos que desea escanear
  • cambie el comando de volcado a od o cualquier utilidad de volcado de archivos que tenga
  • confirme que el comando de corte incluye un espacio inicial y final, así como solo la salida de caracteres hexadecimales de la utilidad de volcado
  • limite la salida de volcado a los primeros 1000 caracteres más o menos por eficiencia

Por ejemplo, algo como esto puede funcionar para usted usando od en lugar de dump :

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

1

dos2unix tiene una opción de información de archivo que se puede usar para mostrar los archivos que se convertirían:

dos2unix -ic /path/to/file

Para hacerlo de forma recursiva, puede usar bashla globstaropción, que para el shell actual está habilitada con shopt -s globstar:

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

Alternativamente, puede usar findpara eso:

find -exec dos2unix -ic {} +            # all files recursively
find -name file -exec dos2unix -ic {} + # files called “file” recursively
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.