Как искать файлы, содержащие окончания строк (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 рекурсивно читать все файлы в каждом каталоге.
pjz
источник
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
Thomee
источник
Я уже взломал это, но все равно спасибо. 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
grep -IUlr $'\r'

объясняетhell.com - grep -IUlr

Стивен Пенни
источник
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$'

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

Linulin
источник
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
источник
3

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

grep -P '\x0d\x0a'

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

grep -P '\x0d\x0d\x0a'

и

grep -P '\x0d\x0d'

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

Питер Y
источник
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$'
MykennaC
источник
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
Десерт
источник