Как искать файлы, содержащие окончания строк (CRLF), с помощью grep в Linux?


126

Я хочу найти файлы, содержащие окончания строки dos, с помощью grep в Linux. Что-то вроде этого:

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

Вышеупомянутое, похоже, соответствует буквальному, rnа это не то, что нужно .

Результат будет передан через xargs в задачи для преобразования crlf в lf, как это

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

2
Вы пробовали dos2unix ? Он автоматически исправляет окончания строк.
sblundy

Я не совсем уверен, но iirc есть разница между цитированием шаблона внутри 'и ". Afaik в шаблонах, заключенных в', escape-последовательности интерпретируются как правильная строка, поэтому '\ r' будет эквивалентно" \\ r "и" \ r "не имеет эквивалента (по крайней мере, в этой записи) с '.
Anticom

Anticom: Вы правы в этом случае, что разница между 'и' не имеет значения; однако, как правило, они различны, поскольку 'окруженные строки являются слабыми кавычками, а "сильными кавычками. Самая большая вещь, которой я пользуюсь, - это то, что расширения $ или `` не расширяются в слабых кавычках ''. См. Bash-hackers при цитировании для получения дополнительной информации.
bschlueter 06

4
Самый простой способ - использовать модерн dos2unixс -icпереключателем. Файлы LF можно искать с помощью unix2dos -ic. Он не изменяет файлы. Только отчет.
gavenkoa

3
поскольку это лучший ответ на любой вопрос, касающийся окончаний строк / возврата каретки в Windows в Linux, я думаю, стоит отметить, что вы можете увидеть их в терминале с помощью команды cat -v somefile.txt; они появляются как^M
user5359531

Ответы:


121

Используйте Ctrl+ V, Ctrl+, Mчтобы ввести буквальный символ возврата каретки в строку grep. Так:

grep -IUr --color "^M"

будет работать - если ^Mесть буквальный CR, который вы вводите, как я предлагал.

Если вам нужен список файлов, вы также хотите добавить эту -lопцию.

объяснение

  • -I игнорировать двоичные файлы
  • -Uпредотвращает удаление символов CR с помощью grep. По умолчанию он сделает это, если решит, что это текстовый файл.
  • -r рекурсивно читать все файлы в каждом каталоге.

3
В качестве быстрого взлома, который сработает, но я думаю, что решение для чтения для человека будет выглядеть следующим образом: grep $ '\ r' / bash shell only / or grepprintf '\r'
akostadinov 04

5
@akostadinov +1, но обратные кавычки интерпретировались из вашего комментария;) Другими словами, второй вариант был бы grep $(printf '\r'). Но для большинства практических применений, связанных с bash, я бы придерживался $'\r'.
jankes

3
Примечание: опция -Uактуальна только для Windows (или cygwin), но там она критична. В Windows без него команда работать не будет.
sleske

3
В чем смысл опции -I? По мануалу мне кажется, что бинарные файлы считаются несоответствующими. Разве комбинация -Iи -U(обеспечивающая двоичный тип) не должна приводить к тому, что все файлы считаются несовпадающими?
Янис Элмерис

3
Вы упоминаете флаг '-l' как дополнительную опцию, но я думаю, что он должен быть включен в основной ответ, потому что вопрос, по сути, запрашивает список файлов. Кроме того, это приводит к более быстрому поиску.
arr_sea

168

grep, вероятно, не тот инструмент, который вам нужен для этого. Он будет печатать строку для каждой совпадающей строки в каждом файле. Если вы, скажем, не хотите запускать задачи 10 раз в файле из 10 строк, grep - не лучший способ сделать это. Используя команду find для запуска файла для каждого файла в дереве, затем поиск по нему для "CRLF" даст вам одну строку вывода для каждого файла, который имеет окончание строки стиля dos:

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

даст вам что-то вроде:

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

Я уже взломал это, но все равно спасибо. grep -IUrl --color '^M' . | xargs -ifile fromdos 'file'
Тим Абелл,

5
Параметр -l для команды grep указывает ему просто перечислить файлы (один раз), а не отображать совпадения в каждом файле.
pjz

8
Не лучшее решение, зависеть от этого (недокументированного, ориентированного на потребление человеком) поведения fileпрограммы. Это очень хрупко. Для (только одного) примера: он не работает с файлами XML, fileотчетами XML document textнезависимо от типа новой строки.
leonbloy

1
@leonbloy, -m /dev/nullна моем find (GNU findutils) 4.4.2(Ubuntu 12.04) эта опция кажется строчной .
EarlCrapstone

8
Мне больше всего нравится этот ответ. Я просто сделалfind . -type f | xargs file | grep CRLF
brianz

58

11
Спасибо! Для ясности тем, кто придет после, в руководстве по bash сказано: «Слова формы $ 'строка' обрабатываются особым образом. Слово расширяется до строки, при этом символы с экранированной обратной косой чертой заменяются, как указано в стандарте ANSI C.» (см. также этот список поддерживаемых кодов )
Шон Гуглер

5
Так это специфично для bash? Следует отметить, если это так.
cubuspl42

для git с плохим autocrlf я бы использовал: grep -IUlrZ $ '\ r' | xargs -0 sed -zbi 's / \ r // g'
buzard

16

Если ваша версия grep поддерживает параметр -P (--perl-regexp) , тогда

grep -lUP '\r$'

может быть использован.


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

Запрос был поиском ... У меня аналогичная проблема ... кто-то отправил смешанные окончания строк в систему контроля версий, так что теперь у нас есть куча файлов с 0x0d 0x0d 0x0aокончаниями строк. Обратите внимание, что

grep -P '\x0d\x0a'

находит все строки, тогда как

grep -P '\x0d\x0d\x0a'

и

grep -P '\x0d\x0d'

не находит строк, поэтому может быть что-то "еще" происходит внутри grep, когда дело доходит до шаблонов окончания строк ... к сожалению для меня!


3

Вы можете использовать команду file в unix. Он дает вам кодировку символов файла вместе с признаками конца строки.

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

1

Если, как и я, ваш минималистичный unix не содержит таких тонкостей, как команда file , а обратная косая черта в ваших выражениях grep просто не работает, попробуйте следующее:

$ 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

Вы можете захотеть внести следующие изменения:

  • настроить команду find, чтобы найти только те файлы, которые вы хотите сканировать
  • измените команду дампа на od или другую имеющуюся у вас утилиту дампа файлов
  • убедитесь, что команда cut включает в себя как начальный, так и конечный пробелы, а также вывод только шестнадцатеричных символов из утилиты дампа
  • ограничьте вывод дампа первыми 1000 символов или около того для эффективности

Например, что-то вроде этого может сработать для вас, используя od вместо dump :

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

1

dos2unix имеет параметр информации о файле, который можно использовать для отображения файлов, которые будут преобразованы:

dos2unix -ic /path/to/file

Чтобы сделать это рекурсивно вы можете использовать bash«s globstarварианта, который для текущей оболочки включен с shopt -s globstar:

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

В качестве альтернативы вы можете использовать findдля этого:

find -exec dos2unix -ic {} +            # all files recursively
find -name file -exec dos2unix -ic {} + # files called “file” recursively
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.