2016-08-12 67 views
0

我有一個文件,它看起來像:如何提取多行模式之間的線條?

blah blah blah blah blah blah blah blah 
    blah blah blah blah blah blah blah blah 
    blah blah blah blah blah blah blah blah 
<empty line here> 
    Total DOS and NOS and partial (IT) DOSDOWN 
<empty line here> 
    E  Total  1 
<empty line here> 
-1.5000 0.004 0.000 0.004 
-1.4953 0.004 0.000 0.004 
-1.4906 0.004 0.000 0.004 
-1.4859 0.004 0.000 0.004 
-1.4812 0.004 0.000 0.004 
0.3563 0.708 5.510 0.708 
0.3609 0.562 5.513 0.562 
0.3656 0.381 5.515 0.381 
0.3703 0.149 5.517 0.149 
<empty line here> 
    Sublattice 1 Atom Fe spin DOWN 

我想是提取(第一圖案)

 Total DOS and NOS and partial (IT) DOSUP  
<empty line here>  
    E  Total  1 
<empty line here> 

和(第二圖案)

<empty line here> 
    Sublattice 1 Atom Fe spin DOWN 

即之間的所有行我想得到

-1.5000 0.004 0.000 0.004 
-1.4953 0.004 0.000 0.004 
-1.4906 0.004 0.000 0.004 
-1.4859 0.004 0.000 0.004 
-1.4812 0.004 0.000 0.004 
0.3563 0.708 5.510 0.708 
0.3609 0.562 5.513 0.562 
0.3656 0.381 5.515 0.381 
0.3703 0.149 5.517 0.149 

因此,在一天結束時,我希望在兩個多行模式之間有行。 據我所知awk可以通過狀態機檢測多行模式(見here),但我沒有做到這一點在我的情況。

任何建議如何解決這個問題將非常感激。

+0

第二圖案可以減少到'<空這裏線>'' – karakfa

+1

AWK -v RS =「NR == 3」 file'將打印文本的第三空白線分隔塊等產生輸出你想要的 - 你不能這樣做的任何原因? –

+1

@EdMorton好的。我使它太複雜了... – hek2mgl

回答

2

下面是根據埃德莫頓的慣用伎倆的解決方案。

awk -v RS= 'n==2; /Total DOS/ || n {n++;next} {n=0}' input.txt 

這是如何工作的。

  • RS=將awk置於多行模式,以便記錄包含行塊。
  • n==2;打印滿足此條件時處理的任何記錄。
  • /RE/ || n是RE(模式)在當前記錄內匹配或變量n非零時評估爲真的條件。
  • {n++;next}明顯增加n並跳到下一條記錄。
  • {n=0}如果我們還沒有跳到下一個記錄,我們重置n

所有這些的影響是,我們打印的記錄是兩個記錄之後的匹配模式。當然,你可以根據自己的喜好調整櫃臺開始的條件。例如,$2=="Total"。鹽適量。

sh-3.2$ cat input.txt 
    blah blah blah blah blah blah blah blah 
    blah blah blah blah blah blah blah blah 
    blah blah blah blah blah blah blah blah 

    Total DOS and NOS and partial (IT) DOSUP 

    E  Total  1 

    -1.5000 0.004 0.000 0.004 
    -1.4953 0.004 0.000 0.004 
    -1.4906 0.004 0.000 0.004 
    ....... ..... ..... ..... 
    0.3609 0.562 5.513 0.562 
    0.3656 0.381 5.515 0.381 
    0.3703 0.149 5.517 0.149 

    blah  blah  blah  blah 

sh-3.2$ awk -v RS= 'n==2; /Total DOS and NOS/||n{n++;next} {n=0}' input.txt 
    -1.5000 0.004 0.000 0.004 
    -1.4953 0.004 0.000 0.004 
    -1.4906 0.004 0.000 0.004 
    ....... ..... ..... ..... 
    0.3609 0.562 5.513 0.562 
    0.3656 0.381 5.515 0.381 
    0.3703 0.149 5.517 0.149 
+0

@glanz - 你能澄清嗎?對於我來說,考慮到你的問題中的輸入數據,這就產生了你在「我想要」中提到的輸出。七行,兩行三行,四行,用點分隔。沒有其他的。有可能您的實際數據在模式之後有兩個空白行,而不僅僅是一個? – ghoti

+0

我認爲'n = 0}'塊只會在'n'已經是'0'時纔會被擊中,所以你可以刪除它,或者如果你想在第一個目標之後重置它,塊被打印。 –

+0

@ghoti @Ed - 你的回答是完全正確的,很好的解釋。我終於明白了爲什麼它不適用於我的原始數據。問題是(並且)在'Total DOS ...'之後的空行之一有一個_invisible_空格符號,因此'awk'不能將它計爲空行。再一次感謝你。 – glanz

1

使用sedsed -n '5,/^$/{/^$/d}'

但是,假定「多起步模式」總是在文件的開頭。否則它會變得更復雜一點。就像這樣:

/Total/{N;N;N} 
/Total.*Total/,/^$/{ 
    /Total/d 
    /^$/d 
} 

在這裏,我假設「合計」多模式的開頭匹配,「總*總」全模式相匹配。將N;N;N替換爲更復雜的東西,如果其他模式以第一行多行模式開頭但少於4行。

1

從您的評論聽起來像所有你需要的是:

awk -v RS= '/Total DOS/{tgt=NR+2} NR==tgt' file 

如果沒有,那麼編輯你的問題澄清。如果您只想要文件輸出中的第一個匹配塊並且效率值得關注,請將其設置爲NR==tgt{print; exit}。根據需要更改正則表達式,以便與需要匹配的Total DOS...行一樣多,以使其具有獨特性。

這是運行鍼對您提供的樣本輸入:

$ cat file 
    blah blah blah blah blah blah blah blah 
    blah blah blah blah blah blah blah blah 
    blah blah blah blah blah blah blah blah 

    Total DOS and NOS and partial (IT) DOSUP 

    E  Total  1 

    -1.5000 0.004 0.000 0.004 
    -1.4953 0.004 0.000 0.004 
    -1.4906 0.004 0.000 0.004 
    ....... ..... ..... ..... 
    0.3609 0.562 5.513 0.562 
    0.3656 0.381 5.515 0.381 
    0.3703 0.149 5.517 0.149 

    blah  blah  blah  blah 

$ awk -v RS= '/Total DOS/{tgt=NR+2} NR==tgt' file 
    -1.5000 0.004 0.000 0.004 
    -1.4953 0.004 0.000 0.004 
    -1.4906 0.004 0.000 0.004 
    ....... ..... ..... ..... 
    0.3609 0.562 5.513 0.562 
    0.3656 0.381 5.515 0.381 
    0.3703 0.149 5.517 0.149 
+0

你的回答是完全正確的。我的原始數據存在的問題是(並且)'Total DOS ...'後面的空行之一有一個_invisible_空格符號,因此'awk'不能將它計爲空行。 – glanz