2009-12-07 69 views
9

如何在下面給出的輸入文件中使用grep輸出字符串'export to excel'的出現?具體來說,如何處理搜索字符串之間發生的換行符? grep中是否有可以執行此操作或其他命令的開關?帶換行符的grep搜索字符串

輸入文件:

文件a.txt中:

等等等等......出口
Excel文檔...
等等等等..

文件B。 txt:

等等等等。 ...導出到Excel ...
等等等等..

+0

據我所知(參考:Unix Power Tools)grep系列程序是面向行的,一次只讀一行,因此無法跨行查找模式。所以你可以考慮一個Perl腳本或在這裏使用sed。 HTH。 – sateesh 2009-12-07 07:29:16

+0

如何在這種情況下使用sed? – 2009-12-07 07:55:16

+0

@Vijay:echo -e「foo \ nbar」| sed -n'N;/foo \ nbar/p' – SiegeX 2009-12-07 08:42:18

回答

6

你只是想找到包含模式的文件,忽略換行符,或者你想真正看到匹配的行?

如果是前者,你可以使用tr來換行轉換爲空格:

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

如果你能做到同樣的事情後,但你可能需要使用-o標誌僅打印實際比賽。然後你需要調整你的正則表達式來包含你想要的任何額外的上下文。

+3

tr + grep解決方案不適合大文件,因爲它將形成一個BIG字符串。 – ghostdog74 2009-12-07 08:47:25

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 
+0

你會如何將實際的行打印爲'grep'(對於其能力範圍內的匹配)? – 2009-12-07 09:30:38

+0

打印記錄,$ 0。否則,我不明白你的意思。 – ghostdog74 2009-12-07 12:40:58

+0

我認爲你的編輯照顧。但是,它在某些邊緣情況下失敗。例如,如果輸入內容類似於「excel導出到\ nexcel」或「導出到\ nsomething以外的excel」。在你的評論中回答你的問題:如果在產出中增加了0美元,那麼最初的一行代碼將不會在OP的問題中指出後顯示「excel」,尤其是「...」。 – 2009-12-07 17:22:12

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

我看不到你用re.MULTILINE編譯正則表達式,那麼它如何檢查另一行上的「excel」? – ghostdog74 2009-12-07 12:45:43

+0

re.MULTILINE是*不是*我想要的,所以我沒有指定它。使用re.MULTILINE,'re'代碼會像字符串的末尾那樣處理換行符,並且在之後不匹配。我想要一個換行符像匹配中的任何其他空白處理。我會在代碼中添加一些註釋。 – steveha 2009-12-07 15:59:35

+0

其實,我的第一個版本可以在有或沒有re.MULTILINE的情況下工作。第二,slurp在整個文件版本不需要那個標誌,因爲它取決於匹配一個換行符。第一個版本創建一個特殊的單行,並剝離過程中的任何換行符。 – steveha 2009-12-07 16:18:22

1

的grep -A1「出口」文件名| grep -B1「excel」

+2

此解決方案不能確保「導出到」位於「excel」旁邊。它將匹配,例如,「出口到\ nblah等等等等等等。」。 – stepthom 2012-08-13 14:45:57

+0

它也與「export \ nto excel」不匹配,並且不縮放以搜索包含許多空格的字符串。 – Keelan 2015-02-02 16:08:47