Grep使用换行符搜索字符串

时间:2009-12-07 06:59:29

标签: bash grep

如何使用grep在下面给出的输入文件中输出字符串'export to excel'的出现次数?具体来说,如何处理搜索字符串之间发生的换行符? grep中是否有可以执行此操作或其他命令的开关?

输入文件:

档案a.txt:

  等等等等......出口到   excel ...
  等等等等。

文件b.txt:

  等等......出口到excel ...
  等等等等。

5 个答案:

答案 0 :(得分:6)

您是否只想查找包含该模式的文件,忽略换行符,或者您是否希望实际看到匹配的行?

如果是前者,您可以使用tr将换行符转换为空格:

tr '\n' ' ' | grep 'export to excel'

如果后者你可以做同样的事情,但你可能想使用-o标志只打印实际匹配。然后,您需要调整正则表达式以包含所需的任何额外上下文。

答案 1 :(得分:2)

我不知道如何在grep中执行此操作。我检查了egrep(1)的手册页,但它与中间的换行符不匹配。

我喜欢@Laurence Gonsalves建议的使用tr(1)消除换行符的解决方案。但正如他所指出的那样,如果你这样做的话,打印匹配的线将是一件痛苦的事。

如果你想匹配一个新行,然后打印匹配的行,我想不出用grep做的方法,但在Python,AWK,Perl的任何一个都不会太难或者Ruby。

这是一个解决问题的Python脚本。我决定,对于仅在连接到前一行时匹配的行,我会在匹配的第二行之前打印-->箭头。完全匹配的行总是在没有箭头的情况下打印。

这是假设/ usr / bin / python是Python 2.x.如果需要,您可以简单地将脚本更改为在Python 3.x下工作。

#!/usr/bin/python

import re
import sys

s_pat = "export\s+to\s+excel"
pat = re.compile(s_pat)

def print_ete(fname):
    try:
        f = open(fname, "rt")
    except IOError:
        sys.stderr.write('print_ete: unable to open file "%s"\n' % fname)
        sys.exit(2)

    prev_line = ""
    i_last = -10
    for i, line in enumerate(f):
        # is ete within current line?
        if pat.search(line):
            print "%s:%d: %s" % (fname, i+1, line.strip())
            i_last = i
        else:
            # construct extended line that included previous
            # note newline is stripped
            s = prev_line.strip("\n") + " " + line
            # is ete within extended line?
            if pat.search(s):
                # matched ete in extended so want both lines printed
                # did we print prev line?
                if not i_last == (i - 1):
                    # no so print it now
                    print "%s:%d: %s" % (fname, i, prev_line.strip())
                # print cur line with special marker
                print "-->  %s:%d: %s" % (fname, i+1, line.strip())
                i_last = i
        # make sure we don't match ete twice
        prev_line = re.sub(pat, "", line)

try:
    if sys.argv[1] in ("-h", "--help"):
        raise IndexError # print help
except IndexError:
    sys.stderr.write("print_ete <filename>\n")
    sys.stderr.write('grep-like tool to print lines matching "%s"\n' %
            "export to excel")
    sys.exit(1)

print_ete(sys.argv[1])

编辑:添加评论。

我遇到了一些麻烦,让它在每一行打印正确的行号,使用的格式类似于grep -Hn的格式。

如果您不需要行号,它可能会更短更简单,您不介意将整个文件一次性读入内存:

#!/usr/bin/python

import re
import sys

# This pattern not compiled with re.MULTILINE on purpose.
# We *want* the \s pattern to match a newline here so it can
# match across multiple lines.
# Note the match group that gathers text around ete pattern uses a character
# class that matches anything but "\n", to grab text around ete.
s_pat = "([^\n]*export\s+to\s+excel[^\n]*)"
pat = re.compile(s_pat)

def print_ete(fname):
    try:
        text = open(fname, "rt").read()
    except IOError:
        sys.stderr.write('print_ete: unable to open file "%s"\n' % fname)
        sys.exit(2)

    for s_match in re.findall(pat, text):
        print s_match

try:
    if sys.argv[1] in ("-h", "--help"):
        raise IndexError # print help
except IndexError:
    sys.stderr.write("print_ete <filename>\n")
    sys.stderr.write('grep-like tool to print lines matching "%s"\n' %
            "export to excel")
    sys.exit(1)

print_ete(sys.argv[1])

答案 2 :(得分:1)

grep -A1“导出到”filename | grep -B1“excel”

答案 3 :(得分:0)

使用gawk。将记录分隔符设置为excel,然后检查“导出到”。

gawk -vRS="excel" '/export.*to/{print "found export to excel at record: "NR}' file

gawk '/export.*to.*excel/{print}
/export to/&&!/excel/{
  s=$0
  getline line
  if (line~/excel/){
   printf "%s\n%s\n",s,line
  } 
}' file

答案 4 :(得分:0)

我对此进行了一些测试,似乎有效:

sed -n '$b; /export to excel/{p; b}; N; /export to\nexcel/{p; b}; D' filename

你可以在行的末尾和开头留出一些额外的空格,如下所示:

sed -n '$b; /export to excel/{p; b}; N; /export to\s*\n\s*excel/{p; b}; D' filename