2009-12-07 36 views
9

Làm cách nào để sử dụng grep cho các lần xuất của chuỗi 'xuất sang excel' trong các tệp đầu vào được đưa ra dưới đây? Cụ thể, cách xử lý các ngắt dòng xảy ra ở giữa các chuỗi tìm kiếm? Có một chuyển đổi trong grep có thể làm điều này hoặc một số lệnh khác có lẽ?Chuỗi tìm kiếm Grep có ngắt dòng

file Input:

file a.txt:

blah blah ... xuất khẩu sang
excel ...
blah blah ..

file b. txt:

blah blah. .. xuất khẩu sang excel ...
blah blah ..

+0

Khi tôi hiểu (tham khảo: Unix Power Tools) grep, các chương trình được định hướng dòng, đọc một dòng tại một thời điểm và do đó không thể tìm thấy các mẫu trên dòng. Vì vậy, bạn có thể nghĩ về một kịch bản perl hoặc sử dụng sed ở đây. HTH. – sateesh

+0

cách sử dụng sed trong ngữ cảnh này? –

+0

@Vijay: echo -e "foo \ nbar" | sed -n 'N;/foo \ nbar/p' – SiegeX

Trả lời

6

Bạn chỉ muốn tìm các file có chứa các mô hình, bỏ qua linebreaks, hay bạn muốn thực sự nhìn thấy những dòng phù hợp?

Nếu trước đây, bạn có thể sử dụng tr để chuyển đổi dòng mới để không gian:

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

Nếu sau này bạn có thể làm điều tương tự, nhưng bạn có thể muốn sử dụng cờ -o để chỉ in thực tế trận đấu. Sau đó, bạn sẽ muốn điều chỉnh regex của mình để bao gồm bất kỳ ngữ cảnh bổ sung nào bạn muốn.

+3

tr + grep giải pháp không thực sự phù hợp cho các tập tin lớn như nó sẽ hình thành một chuỗi lớn. – ghostdog74

0

sử dụng gawk. đặt dấu phân tách bản ghi là excel, sau đó kiểm tra "xuất sang".

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

hoặc

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

Bạn sẽ in các dòng thực như 'grep' sẽ (đối với các kết quả phù hợp trong khả năng của nó) như thế nào? –

+0

in bản ghi, $ 0. Nếu không, tôi không hiểu ý bạn là gì. – ghostdog74

+0

Tôi nghĩ rằng chỉnh sửa của bạn sẽ giải quyết vấn đề đó. Tuy nhiên, nó không thành công cho một số trường hợp cạnh. Nếu đầu vào là một cái gì đó như "excel xuất khẩu để \ nexcel" hoặc "xuất khẩu sang \ nsomething khác excel", ví dụ. Để trả lời câu hỏi của bạn trong nhận xét của bạn: một lớp lót gốc, nếu $ 0 được thêm vào đầu ra, sẽ không hiển thị "excel" và đặc biệt là "..." sau khi được chỉ ra trong câu hỏi của OP. –

0

Tôi đã thử nghiệm này một chút và có vẻ như để làm việc:

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

Bạn có thể cho phép một số không gian màu trắng thêm ở cuối và đầu dòng như thế này:

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

Tôi không biết làm thế nào để làm điều này trong grep. Tôi đã kiểm tra trang người đàn ông cho egrep(1) và nó không thể phù hợp với một dòng mới ở giữa.

Tôi thích giải pháp @Laurence Gonsalves đề xuất, sử dụng tr(1) để xóa các dòng mới. Nhưng như ông đã lưu ý, nó sẽ là một nỗi đau để in các dòng phù hợp nếu bạn làm theo cách đó.

Nếu bạn muốn kết hợp mặc dù dòng mới và sau đó in (các) dòng phù hợp, tôi không thể nghĩ ra cách để làm điều đó với grep, nhưng nó sẽ không quá khó trong bất kỳ Python, AWK, Perl, hoặc Ruby.

Đây là tập lệnh Python giải quyết được sự cố. Tôi quyết định rằng, đối với các dòng chỉ khớp khi được nối với dòng trước đó, tôi sẽ in một mũi tên --> trước dòng thứ hai của trận đấu. Các đường thẳng hoàn toàn luôn được in mà không có mũi tên.

Điều này được viết giả định rằng/usr/bin/python là Python 2.x.Bạn có thể thay đổi kích thước kịch bản để làm việc theo Python 3.x nếu muốn.

#!/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]) 

EDIT: thêm nhận xét.

Tôi đã gặp một số sự cố để làm cho nó in đúng số dòng trên mỗi dòng, sử dụng một định dạng tương tự như những gì bạn sẽ nhận được với grep -Hn.

Nó có thể là ngắn hơn nhiều và đơn giản hơn nếu bạn không cần số dòng, và bạn không nhớ đọc trong toàn bộ tập tin cùng một lúc vào bộ nhớ:

#!/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]) 
+0

Tôi không thấy bạn đã biên dịch regex bằng re.MULTILINE, vậy làm cách nào để kiểm tra "excel" trên một dòng khác? – ghostdog74

+0

re.MULTILINE là * không * những gì tôi muốn, vì vậy tôi đã không chỉ định nó. Với re.MULTILINE, mã 're' xử lý một dòng mới như kết thúc của một chuỗi và không khớp với sau đó. Tôi muốn một dòng mới được xử lý giống như bất kỳ không gian màu trắng khác trong kết hợp. Tôi sẽ thêm một số nhận xét vào mã. – steveha

+0

Trên thực tế, phiên bản đầu tiên của tôi sẽ hoạt động tương tự với hoặc không có re.MULTILINE. Phiên bản thứ hai, slurp-in-whole-file cần không có cờ đó vì nó phụ thuộc vào việc khớp với một dòng mới. Phiên bản đầu tiên xây dựng một dòng đơn đặc biệt và loại bỏ bất kỳ dòng mới nào trong tiến trình. – steveha

1

grep -A1 "xuất khẩu sang" tên tệp | grep -B1 "excel"

+2

Giải pháp này không đảm bảo rằng "xuất sang" bên cạnh "excel". Nó sẽ phù hợp, ví dụ, "xuất khẩu sang \ nblah blah blah blah excel". – stepthom

+0

Nó cũng không khớp với "xuất \ thành excel" và không mở rộng để tìm kiếm chuỗi chứa nhiều khoảng trắng. – Keelan

Các vấn đề liên quan