Como você procura por arquivos que contenham terminações de linha dos (CRLF) com grep no Linux?

126

Quero procurar arquivos que contenham terminações de linha dos com grep no Linux. Algo assim:

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

O texto acima parece corresponder ao literal, rnque não é o que é desejado.

A saída disso será canalizada através de xargs em todos para converter crlf em lf assim

grep -IUrl --color '^M' . | xargs -ifile fromdos 'file'
Tim Abell
fonte
2
Você já experimentou o dos2unix ? Ele corrige as terminações de linha automaticamente.
sblundy 16/09/08
Não tenho muita certeza, mas existem algumas diferenças entre citar o padrão dentro de 'e ". Após os padrões contidos em' as seqüências de escape são interpretadas como uma sequência adequada, portanto '\ r' seria equivalente a" \\ r "e" \ r "não tem equivalente (pelo menos nessa notação) com '.
Anticom 16/10
Anticom: Você está correto, neste caso, que a diferença entre 'e "é irrelevante; no entanto, geralmente elas são distintas, pois' as cordas cercadas são fracas entre aspas e 'são fortes entre aspas. A maior coisa de que aproveito é que as expansões de $ ou `` não se expandem em strings fracas entre aspas. Veja bash-hackers sobre citações para mais.
precisa saber é o seguinte
4
A maneira mais fácil é usar o moderno dos2unixcom o -icswitch. Para arquivos LF, você pode pesquisar com o unix2dos -ic. Não modifica arquivos. Apenas reporte.
precisa saber é o seguinte
3
como esta é a resposta principal para qualquer pergunta sobre terminações de linha do Windows / retornos de carro no Linux, acho importante notar que você pode vê- los no terminal com o comando cat -v somefile.txt; eles aparecem como^M
user5359531 15/10

Respostas:

121

Use Ctrl+ V, Ctrl+ Mpara inserir um caractere literal de retorno de carro em sua string grep. Assim:

grep -IUr --color "^M"

funcionará - se ^Mhouver um CR literal que você insira como sugeri.

Se você deseja a lista de arquivos, também deseja adicionar a -lopção.

Explicação

  • -I ignorar arquivos binários
  • -Uimpede que o grep retire caracteres CR. Por padrão, ele faria isso se decidir que é um arquivo de texto.
  • -r leia todos os arquivos em cada diretório recursivamente.
pjz
fonte
3
Como um corte rápido que iria trabalhar, mas eu acho solução readbale humana seria: grep $ '\ r' / shell bash only / ou grepprintf '\r'
akostadinov
5
@akostadinov +1, mas os backticks foram interpretados a partir do seu comentário;) A segunda opção seria, em outras palavras, ser grep $(printf '\r'). Mas para os usos mais práticos que envolvem o bash, eu continuaria $'\r'.
jankes
3
Nota: A opção -Ué relevante apenas para Windows (ou cygwin), mas é fundamental aqui. No Windows, o comando não funcionará sem ele.
Sleske
3
Qual é o ponto de opção -I? Pelo manual, parece-me que os arquivos binários são considerados sem correspondência. A combinação de -Ie -U(que impõe o tipo binário) não deve resultar em todos os arquivos considerados como não correspondentes?
Jānis Elmeris
3
Você mencionou o sinalizador '-l' como uma opção de complemento, mas acho que ele deve ser incluído na resposta principal, porque a pergunta solicita essencialmente uma lista de arquivos. Além disso, resulta em uma pesquisa mais rápida.
arr_sea
167

grep provavelmente não é a ferramenta que você deseja para isso. Irá imprimir uma linha para cada linha correspondente em cada arquivo. A menos que você queira, digamos, executar todos 10 vezes em um arquivo de 10 linhas, o grep não é a melhor maneira de fazer isso. Usar o find para executar o arquivo em todos os arquivos da árvore e, em seguida, procurar por "CRLF" obterá uma linha de saída para cada arquivo que possui finais de linha com estilo dos:

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

você terá 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
Tomé
fonte
Eu já tinha quebrado isso, mas obrigado de qualquer maneira. grep -IUrl --color '^M' . | xargs -ifile fromdos 'file'
Tim Abell
5
A opção -l para grep diz para listar apenas os arquivos (uma vez) em vez de listar as correspondências em cada arquivo.
pjz
7
Não é uma boa solução, depender desse comportamento (não documentado, orientado ao consumo humano) do fileprograma. Isso é muito frágil. Por (apenas um) exemplo: ele não funciona com arquivos XML, filerelatórios XML document textindependentemente do tipo de nova linha.
Leonbloy #
1
@leonbloy, a opção parece ser minúscula -m /dev/nullno meu find (GNU findutils) 4.4.2(Ubuntu 12.04).
precisa saber é o seguinte
7
Eu gosto desta resposta da melhor maneira. Eu simplesmente fizfind . -type f | xargs file | grep CRLF
brianz
58
grep -IUlr $'\r'

explicaçãoshell.com - grep -IUlr

Steven Penny
fonte
11
Obrigado! Para maior clareza dos que vierem depois, o manual do bash diz "As palavras da forma $ 'string' são tratadas especialmente. A palavra se expande para string, com caracteres escapados por barra invertida substituídos conforme especificado pelo padrão ANSI C." (ver também esta lista de códigos suportados )
Sean Gugler
5
Então isso é específico do bash? Deve-se notar se for.
cubuspl42
para git com mal autocrlf, eu usaria: grep -IUlrZ $ '\ r' | xargs -0 sed -zbi 's / \ r // g'
buzard 21/02
16

Se sua versão do grep suportar a opção -P (--perl-regexp) , então

grep -lUP '\r$'

poderia ser usado.

Linulin
fonte
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
fonte
3

A consulta foi de pesquisa ... Eu tenho um problema semelhante ... alguém enviou finais de linha mistos no controle de versão, então agora temos um monte de arquivos com 0x0d 0x0d 0x0afinais de linha. Observe que

grep -P '\x0d\x0a'

encontra todas as linhas, enquanto

grep -P '\x0d\x0d\x0a'

e

grep -P '\x0d\x0d'

não encontra nenhuma linha, então pode haver algo "mais" acontecendo dentro do grep quando se trata de padrões de final de linha ... infelizmente para mim!

Peter Y
fonte
3

Você pode usar o comando file no unix. Ele fornece a codificação de caracteres do arquivo junto com os terminadores de linha.

$ file myfile
myfile: ISO-8859 text, with CRLF line terminators
$ file myfile | grep -ow CRLF
CRLF  
Murali Krishna Parimi
fonte
1

Se, como eu, seu unix minimalista não inclui detalhes como o comando file , e as barras invertidas em suas expressões grep simplesmente não cooperam, tente o seguinte:

$ 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

As modificações que você pode querer fazer no item acima incluem:

  • ajuste o comando find para localizar apenas os arquivos que você deseja verificar
  • altere o comando dump para od ou qualquer utilitário de despejo de arquivo que você tenha
  • confirme se o comando recortar inclui um espaço inicial e final, bem como apenas a saída de caracteres hexadecimais do utilitário dump
  • limitar a saída de despejo aos primeiros 1000 caracteres ou mais, para obter eficiência

Por exemplo, algo assim pode funcionar para você usando od em vez de dump :

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

dos2unix possui uma opção de informações do arquivo que pode ser usada para mostrar os arquivos que seriam convertidos:

dos2unix -ic /path/to/file

Para fazer isso recursivamente, você pode usar basha globstaropção 's' , que para o shell atual é ativada com shopt -s globstar:

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

Como alternativa, você pode usar findpara isso:

find -exec dos2unix -ic {} +            # all files recursively
find -name file -exec dos2unix -ic {} + # files called “file” recursively
sobremesa
fonte