您如何在Linux上使用grep搜索包含dos行尾(CRLF)的文件?


125

我想在Linux上搜索包含grep的dos行结尾的文件。像这样:

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

上面的内容似乎与原义相符,rn这不是所希望的。

这样的输出将通过xargs传递到todos,以将crlf转换为lf,如下所示

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

2
您尝试过dos2unix吗?它会自动修复行尾。
sblundy

我不太确定,但是iirc引用'和'内的模式之间有区别。'包围在'模式中的Afaik转义序列被解释为正确的字符串,因此'\ r'等效于“ \\ r”和“ \ R”具有(在该符号至少)没有等效与”。
Anticom

Anticom:在这种情况下,'和'之间的区别无关紧要;但是,通常来说,它们是不同的,因为'包围的字符串用弱引号引起来,而“用强引号引起来。我最大的优势是$扩展名或``不要在弱引用的字符串中扩展。有关更多信息,请参见bash黑客
bschlueter'1

4
最简单的方法是将现代功能dos2unix-ic开关配合使用。对于LF文件,您可以使用unix2dos搜索-ic。它不会修改文件。仅报告。
gotnkoa

3
因为这是有关Linux上Windows行尾/回车的任何问题的最佳答案,所以我认为值得一提的是,您可以在终端中使用以下命令查看它们cat -v somefile.txt:他们显示为^M
user5359531

Answers:


121

使用Ctrl+ VCtrl+ M在grep字符串中输入文字的回车符。所以:

grep -IUr --color "^M"

将有效-如果^M您按照我的建议输入了文字CR。

如果需要文件列表,则也要添加该-l选项。

说明

  • -I 忽略二进制文件
  • -U防止grep剥离CR字符。默认情况下,如果它决定是一个文本文件,它将执行此操作。
  • -r 递归读取每个目录下的所有文件。

3
作为一个可行的快速技巧,但我认为人类readbale解决方案将是:grep $'\ r'/仅bash shell /或grepprintf '\r'
akostadinov 2012年

5
@akostadinov +1,但是您的评论中没有反引号;)换句话说,第二种选择是grep $(printf '\r')。但是对于涉及bash的大多数实际用途,我会坚持使用$'\r'
jankes 2012年

3
注意:该选项-U仅与Windows(或cygwin)相关,但在此非常重要。在Windows上,如果没有该命令,该命令将不起作用。
sleske

3
选择的重点是-I什么?根据手册,在我看来,二进制文件被认为是不匹配的。-I-U(强制执行二进制类型)的组合是否应导致所有文件都被视为不匹配?
亚尼斯Elmeris

3
您提到了“ -l”标志作为附加选项,但是我认为应该将其包含在主要答案中,因为该问题实质上要求提供文件列表。此外,它还可以加快搜索速度。
arr_sea 2015年

166

grep可能不是您想要的工具。它将为每个文件中的每个匹配行打印一行。除非您想在10行文件中运行todo 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'
Tim Abell

5
grep的-l选项告诉它仅列出文件一次(而不是列出每个文件中的匹配项)。
pjz

7
依靠file程序的行为(未记录,面向人类消费)不是一个好的解决方案。这是非常脆弱的。对于(仅一个)示例:它不适用于XML文件,无论换行符类型如何,都将生成file报告XML document text
leonbloy

1
@leonbloy,该选项-m /dev/null在我的find (GNU findutils) 4.4.2(Ubuntu 12.04)上似乎是小写字母。
EarlCrapstone 2014年

7
我最喜欢这个答案。我只是做过find . -type f | xargs file | grep CRLF
brianz

58
grep -IUlr $'\r'

describeshell.com-grep -IUlr


11
谢谢!为了使以后的读者清楚,bash手册说:“ $'string'形式的单词经过特殊处理。单词扩展为字符串,并按ANSI C标准的规定替换了反斜杠转义的字符。” (另请参阅此受支持代码列表
Sean Gugler 2014年

5
那么这是bash特有的吗?应该注意的是。
cubuspl42 '16

对于git的autocrlf严重,我将使用:grep -IUlrZ $'\ r'| xargs的-0 SED -zbi的/ \ 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

您可以在Unix中使用file命令。它为您提供文件的字符编码以及行终止符。

$ 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命令以仅找到要扫描的文件
  • dump命令更改为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

要递归地执行此操作,可以使用bashglobstar选项,该选项针对当前外壳启用了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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.