Regex grep匹配,但如果行以dos ^M结尾,则不打印

Regex grep匹配,但如果行以dos ^M结尾,则不打印,regex,bash,grep,Regex,Bash,Grep,我需要在多个文件中搜索一个模式,如果找到显示文件,线和由几个额外字符包围的模式。我的问题是,如果匹配模式的行以^M(CRLF)结尾,grep将打印一个空行 创建这样的文件,第一行“a^M”,第二行“a”,第三行空行,第四行“a”(后面不跟新行) 在找到并显示模式后,无需尝试匹配几个字符: # grep -srnoEiI ".{0,2}a" * 1:a 2:a 4:a 如果我尝试匹配图案末尾的任何字符,它将打印一个空行,而不是以CRLF结尾的第一行: # grep -srnoEiI ".{0,2

我需要在多个文件中搜索一个模式,如果找到显示文件,线和由几个额外字符包围的模式。我的问题是,如果匹配模式的行以^M(CRLF)结尾,grep将打印一个空行

创建这样的文件,第一行“a^M”,第二行“a”,第三行空行,第四行“a”(后面不跟新行)

在找到并显示模式后,无需尝试匹配几个字符:

# grep -srnoEiI ".{0,2}a" *
1:a
2:a
4:a
如果我尝试匹配图案末尾的任何字符,它将打印一个空行,而不是以CRLF结尾的第一行:

# grep -srnoEiI ".{0,2}a.{0,2}" *

2:a
4:a
我如何才能将此更改为按预期操作

另外,我想修复这个grep,但我会接受其他解决方案,例如在awk中

编辑:

根据下面的答案,我选择剥离\r并强制grep将颜色管道传输到tr:

grep --color=always -srnoEiI ".{0,2}a.{0,2}" * | tr -d '\r'

这两种方法都可以:查找模式,查看行是否以回车结束,打印行号和行。对于sed,行号在它自己的行上,因此我们必须用冒号连接两个连续的行


这两种方法都可以:查找模式,查看行是否以回车结束,打印行号和行。对于sed,行号在它自己的行上,因此我们必须用冒号连接两个连续的行。

这里有一个更简单的情况重现您的问题:

# Output 
echo $'a\r' | grep -o "a"
# No output
echo $'a\r' | grep -o "a."
这是因为
^M
像普通字符一样匹配,并使终端覆盖其输出(这纯粹是装饰性的)

您想如何解决此问题取决于您想做什么

# Show the output in hex format to ensure it's correct
$ echo $'a\r' | grep -o "a." | od -t x1 -c
0000000  61  0d  0a
      a  \r  \n

# Show the output in visually less ambiguous format
$ echo $'a\r' | grep -o "a." | cat -v
a^M

# Strip the carriage return
$ echo $'a\r' | grep -o "a." | tr -d '\r'
a

这里有一个更简单的例子再现了您的问题:

# Output 
echo $'a\r' | grep -o "a"
# No output
echo $'a\r' | grep -o "a."
这是因为
^M
像普通字符一样匹配,并使终端覆盖其输出(这纯粹是装饰性的)

您想如何解决此问题取决于您想做什么

# Show the output in hex format to ensure it's correct
$ echo $'a\r' | grep -o "a." | od -t x1 -c
0000000  61  0d  0a
      a  \r  \n

# Show the output in visually less ambiguous format
$ echo $'a\r' | grep -o "a." | cat -v
a^M

# Strip the carriage return
$ echo $'a\r' | grep -o "a." | tr -d '\r'
a
还有两种方法:

使用将dos样式的行尾转换为unix样式:

dos2unix myfile.txt
或删除CR字符,然后通过管道连接到grep:

$ tr -d '\r' < myfile.txt | grep -srnoEiI ".{0,2}a.{0,2}"
1:a
2:a
4:a
$
$tr-d'\r'
注意:可能需要在您使用的任何操作系统上安装
dos2unix
。非常可能。

还有两种方法:

使用将dos样式的行尾转换为unix样式:

dos2unix myfile.txt
或删除CR字符,然后通过管道连接到grep:

$ tr -d '\r' < myfile.txt | grep -srnoEiI ".{0,2}a.{0,2}"
1:a
2:a
4:a
$
$tr-d'\r'

注意:可能需要在您使用的任何操作系统上安装
dos2unix
。非常有可能。

您可以使用
pcregrep

pcregrep -n '.{0,2}a.{0,2}' inputfile
对于您的示例输入:

$ printf $'a\r\na\n\na\n' | pcregrep -n '.{0,2}a.{0,2}' 
1:a
2:a
4:a

您可以使用
pcregrep

pcregrep -n '.{0,2}a.{0,2}' inputfile
对于您的示例输入:

$ printf $'a\r\na\n\na\n' | pcregrep -n '.{0,2}a.{0,2}' 
1:a
2:a
4:a

您可以将awk与自定义字段分隔符一起使用:

awk -F '[[:blank:]\r]' '/.{0,2}a.{0,2}/{print FILENAME, NR, $1}' OFS=':' file
测试:

您的grep命令:

grep -srnoEiI ".{0,2}a.{0,2}" file|cat -vte
file:1:a^M$
file:2:a$
file:4:a$
建议的awk命令:

awk -F '[[:blank:]\r]' '/.{0,2}a.{0,2}/{print FILENAME, NR, $1}' OFS=':' file|cat -vte
file:1:a$
file:2:a$
file:4:a$

您可以将awk与自定义字段分隔符一起使用:

awk -F '[[:blank:]\r]' '/.{0,2}a.{0,2}/{print FILENAME, NR, $1}' OFS=':' file
测试:

您的grep命令:

grep -srnoEiI ".{0,2}a.{0,2}" file|cat -vte
file:1:a^M$
file:2:a$
file:4:a$
建议的awk命令:

awk -F '[[:blank:]\r]' '/.{0,2}a.{0,2}/{print FILENAME, NR, $1}' OFS=':' file|cat -vte
file:1:a$
file:2:a$
file:4:a$

使用
dos2unix
实用程序是否可以将CRLF结尾转换为LF?您的预期输出是什么?@digitaltrampa,不,我正在搜索+4GB的源代码文件,我不想全部触摸和更改。@anubhava上述第一个和第二个grep示例中的输出应该是相同的,即您的“| cat-vte”正在生成预期的输出。感谢您的回答,在多次阅读您的问题后,我意识到您的问题,因此发布了一个答案。使用
dos2unix
实用程序是否可以将CRLF结尾转换为LF?您的预期输出是什么?@digitaltrama,不,我正在搜索+4GB的源代码文件,我不想触摸和更改它们。@anubhava在上面的第一个和第二个grep示例中,输出应该是相同的,您的“| cat-vte”正在生成预期的输出。感谢您的回答,在阅读了您的问题几次之后,我意识到您在问什么,因此发布了一个答案。