Como testar se um arquivo usa CRLF ou LF sem modificá-lo?

40

Eu preciso executar periodicamente um comando que garanta que alguns arquivos texto sejam mantidos no modo Linux. Infelizmente dos2unix sempre modifica o arquivo, o que bagunçaria os registros de data e hora da pasta e causaria gravações desnecessárias.

O script que eu escrevo está no Bash, então prefiro respostas baseadas no Bash.

    
por Adam Ryczkowski 17.06.2013 / 18:34

10 respostas

38

Você pode usar dos2unix como filtro e comparar sua saída com o arquivo original:

dos2unix < myfile.txt | cmp -s - myfile.txt
    
por 17.06.2013 / 22:42
21

Se o objetivo é apenas evitar a afetação do registro de data e hora, dos2unix tem a opção -k ou --keepdate , que manterá o registro de data e hora igual. Ele ainda terá que fazer uma gravação para criar o arquivo temporário e renomeá-lo, mas seus timestamps não serão afetados.

Se qualquer modificação do arquivo for inaceitável, você pode usar a seguinte solução de esta resposta .

find . -not -type d -exec file "{}" ";" | grep CRLF
    
por 17.06.2013 / 18:48
17

Você pode tentar grep do código CRLF, octal:

grep -U $'5' myfile.txt

ou hex:

grep -U $'\x0D' myfile.txt
    
por 17.06.2013 / 19:11
15

Como a versão 7.1 dos2unix tem uma opção -i , --info para obter informações sobre quebras de linha. Você pode usar o dos2unix para testar quais arquivos precisam de conversão.

Exemplo:

dos2unix -ic *.txt | xargs dos2unix
    
por 22.09.2015 / 21:13
12

Primeiro método ( grep ):

Conte as linhas que contêm um retorno de carro:

[[ $(grep -c $'\r' myfile.txt) -gt 0 ]] && echo dos

Conte as linhas que terminam com <> um retorno de carro:

[[ $(grep -c $'\r$' myfile.txt) -gt 0 ]] && echo dos

Estes serão tipicamente equivalentes; um retorno de carro no interior de uma linha (ou seja, não no final) é raro.

Mais eficiente:

grep -q $'\r' myfile.txt && echo dos

Isso é mais eficiente

  1. porque não precisa converter a contagem em uma string ASCII, e depois converter essa string de volta para um inteiro e compará-la a zero, e
  2. porque grep -c precisa ler o arquivo inteiro contar todas as ocorrências do padrão, enquanto grep -q pode sair ao ver a primeira ocorrência do padrão.

Notas:

  • Por todo o texto acima, você pode precisar adicionar a opção -U (por exemplo, use -cU ou -qU ), porque GNU grep adivinha se o arquivo é um arquivo de texto. Se ele acha que o arquivo é texto, ele ignora os retornos de carro nas extremidades das linhas, em uma tentativa de fazer com que $ em expressões regulares funcione "corretamente" - mesmo se a expressão regular for \r$ ! A especificação de -U (ou --binary ) substitui essa suposição, fazendo com que grep trate o (s) arquivo (s) como binário e passar os dados para o mecanismo de correspondência textualmente, com as terminações CR intactas.
  • Não faça grep … $'\r\n' myfile.txt , porque grep trata \n como um delimitador de padrão. Assim como grep -E 'foo|' procura linhas contendo foo ou uma string nula, grep $'\r\n' procura linhas contendo \r ou uma string nula, e cada linha corresponde a uma string nula.

Segundo método ( file ):

[[ $(file myfile.txt) =~ CRLF ]] && echo dos

porque file informa algo como:

myfile.txt: UTF-8 Unicode text, with CRLF line terminators

Variante mais segura:

[[ $(file -b - < myfile.txt) =~ CRLF ]] && echo dos

onde

Cuidado com a verificação da saída de file pode não funcionar em uma localidade diferente do inglês.

    
por 17.06.2013 / 18:51
5

Use cat -A

$ cat file
hello
hello

Agora, se esse arquivo foi criado em sistemas * NIX, ele será exibido

$ cat -A file
hello$
hello$

Mas se esse arquivo foi criado no Windows, ele será exibido

$ cat -A file
hello^M$
hello

^M representa CR e $ representa LF . Observe que o Windows não salvou a última linha com CRLF

Isso também não altera o conteúdo do arquivo.

    
por 31.08.2017 / 22:54
4

uma função bash para você:

# return 0 (true) if first line ends in CR
isDosFile() {
    [[ $(head -1 "$1") == *$'\r' ]]  
}

Então você pode fazer coisas como

streamFile () {
    if isDosFile /tmp/foo.txt; then
        sed 's/\r$//' "$1"
    else
        cat "$1"
    fi
}

streamFile /tmp/foo.txt | process_lines_without_CR
    
por 17.06.2013 / 19:41
4

Se um arquivo tiver terminações de linha CR-LF no estilo DOS / Windows, se você olhar para ele usando uma ferramenta baseada em Unix, verá caracteres CR ('\ r') no final de cada linha.

Este comando:

grep -l '^M$' filename

imprimirá filename se o arquivo contiver uma ou mais linhas com terminações de linha no estilo do Windows e não imprimirá nada se isso não acontecer. Exceto que ^M tem que ser um caractere de retorno de carro literal, normalmente inserido no terminal digitando Ctrl + V seguido por Enter (ou Ctrl + V e depois Ctrl + M ). O shell bash permite que você escreva um retorno de carro literal como $'\r' ( documentado aqui ), então você pode escrever:

grep -l $'\r$' filename

Outras camadas podem fornecer uma característica semelhante.

Você pode usar outra ferramenta:

awk '/\r$/ { exit(1) }' filename

Isso sairá com um status de 1 (configurando $? para 1 ) se o arquivo contiver qualquer final de linha no estilo do Windows e com um status 0 , se não tiver, tornando útil em uma instrução shell if (observe a falta de [ colchetes ] ):

if awk '/\r$/ { exit(1) }' filename ; then
    echo filename has Unix-style line endings
else
    echo filename has at least one Windows-style line ending
fi

Um arquivo pode conter uma mistura de terminações de linha estilo Unix e estilo Windows. Estou assumindo aqui que você deseja detectar arquivos que tenham quaisquer terminações de linha no estilo do Windows.

    
por 17.06.2013 / 21:06
2

Use file :

$ file README.md
README.md: ASCII text, with CRLF line terminators

$ dos2unix README.md
dos2unix: converting file README.md to Unix format...

$ file README.md
README.md: ASCII text
    
por 10.05.2018 / 17:45
1

Eu tenho usado

cat -v filename.txt | diff - filename.txt

que parece funcionar. Eu acho a saída um pouco mais fácil de ler do que

dos2unix < filename.txt | diff - filename.txt

Também é útil se você não puder instalar dos2unix por algum motivo.

    
por 03.10.2016 / 12:39