¿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'
Tim Abell
fuente
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.
pjz
fuente
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
Thomee
fuente
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

Steven Penny
fuente
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.

Linulina
fuente
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
yabt
fuente
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í!

Peter Y
fuente
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  
Murali Krishna Parimi
fuente
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$'
MykennaC
fuente
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
postre
fuente