2013-05-22 38 views
1

我需要能夠搜索字符串(允許使用4320101),在字符串上方打印20行並在打印後這一點,直到找到字符串爲字符串搜索(例如awk,grep,sed),然後查找上面的X行和下面的另一個字符串

例如:

​​

我只是想輸出到一個文件中的下列結果:

16 Apr 2013 00:14:15 
id="4320101" 
</eventUpdate> 

有一個文件中,這些羣體的文本的多個實例我想。

我試着用下面這樣:

cat filename | grep "</eventUpdate>" -A 20 4320101 -B 100 > greptest.txt 

但它永遠只能顯示字符串的20線兩側。

注:
- 行號文是上是不一致的,所以我不能去關閉這些,因此爲什麼我使用-A 20
- 理想我寧願它,所以當它的字符串搜索後, ,它發現後停止,然後進行搜索。

摘要:找到4320101,輸出20線之上4320101(空白或一條線),並低於4320101然後輸出的所有行組成

</eventUpdate> 

做研究,我不確定如何獲得awk中, nawk或sed在我的工作上做這件事。

+1

'-A'是grep將在匹配行後面打印'A'的行數。如果你不想在匹配的行之後有任何行,爲什麼你要求20行?我也不明白你對線號不一致的評論,但如果你想要20行'B'efore,使用'-B 20' – rici

+0

我明白了。這應該可以工作:cat filename | grep 4320101 -A 100 -B 20,但它返回::沒有這樣的文件或目錄 – Zippyduda

+0

我意識到方式-A和-B的作品是它需要值的文件名,所以它認爲eventUpdate是一個文件。但是,我想只搜索eventUpdate(給它100行以在4320101之下找到它) – Zippyduda

回答

1

這可能會爲你工作(GNU SED):

sed ':a;s/\n/&/20;tb;$!{N;ba};:b;/4320102/!D;:c;n;/<\/eventUpdate>/!bc' file 

編輯:

  • :a;s/\n/&/20;tb;$!{N;ba};這樣可保持20行的窗口模式空間(PS)
  • :b;/4320102!D;這會通過文件移動上述窗口,直到找到4320102的模式。
  • :c;n;/<\/eventUpdate>/!bc打印20行窗口,並找到任何後續行,直到找到<\/eventUpdate>圖案。
+0

這工作完美。只是修改它來檢查3行,讀取用戶輸入的讀取ID(在本例中爲4320102),然後執行/'$ ID'。但我必須問,你能分解所有這一切嗎? – Zippyduda

+0

@Zippyduda見編輯。 – potong

1

這裏是一個醜陋的awk解決方案:)

awk 'BEGIN{last=1} 
{if((length($0)==0) || (Random ~ $0))last=NR} 
/4320101/{flag=1; 
if((NR-last)>20) last=NR-20; 
cmd="sed -n \""last+1","NR-1"p \" input.txt"; 
system(cmd); 
} 
flag==1{print} 
/eventUpdate/{flag=0}' <filename> 

所以基本上它的作用是跟蹤在最後一個空白行或線路包含在last變量Random格局。現在,如果找到4320101,則通過system sed命令從that line -20 or last中較近者打印。並設置flagflag導致下一行開始打印,直到找到eventUpdate。雖然沒有經過測試,但應該是工作

1

在sed/awk中後退總是很棘手..這個自包含的awk腳本基本上保留了最後20行存儲,當它到達4320101它打印這些存儲的行,向上直到找到空白或不需要的行,然後停止。此時它會切換到printall模式並打印所有行,直到遇到eventUpdate,然後打印並退出。

awk ' 
function store(line) { 
    for(i=0; i <= 20; i++) { 
     last[i-1] = last[i]; i++; 
    }; 
    last[20]=line; 
}; 
function purge() { 
    for(i=20; i >= 0; i--) { 
     if(length(last[i])==0 || last[i] ~ "Random") { 
      stop=i; 
      break 
     }; 
    }; 
    for(i=(stop+1); i <= 20; i++) { 
     print last[i]; 
    }; 

}; 
{ 
store($0); 
if(/4320101/) { 
    purge(); 
    printall=1; 
    next; 
}; 
if(printall == 1) { 
    print; 
    if(/eventUpdate/) { 
     exit 0; 
    }; 
}; 
}' test 
1

你可以嘗試這樣的事情 -

awk '{ 
    a[NR] = $0 
} 

/<\/eventUpdate>/ { 
    x = NR 
} 

END { 
    for (i in a) { 
     if (a[i]~/4320101/) { 
      for (j=i-20;j<=x;j++) { 
      print a[j] 
      } 
     } 
    } 
}' file 
0

最簡單的方法是使用2次的文件 - 首先確定在其中你的目標正則表達式中發現該範圍內的行號,第二個打印選定範圍內的行,例如:

awk ' 
NR==FNR { 
    if ($0 ~ /\<4320101\>/ { 
     for (i=NR-20;i<NR;i++) 
      range[i] 
     inRange = 1 
    } 
    if (inRange) { 
     range[NR] 
    } 
    if ($0 ~ /<\/eventUpdate>/) { 
     inRange = 0 
    } 
    next 
} 
FNR in range 
' file file 
+0

使用這個我得到了:awk:cmd。第9行:(FILENAME = test FNR = 482)fatal:嘗試使用標量'inRange'作爲數組 – Zippyduda

+0

修復。 awk確實將你指向錯誤所在的行,並告訴你錯誤是什麼。 –

1

讓我們來看看,如果我理解您的需求:

你有兩個字符串,我會打電話給KEYLIMIT。而要打印:

  1. 最多包含20 KEY線前行,但停藥,如果有一個空行。

  2. 包含KEY的行與包含LIMIT的以下行之間的所有行。 (這忽略你的要求有不超過100個這樣的行;如果這是很重要的,它是相對簡單的補充。)

完成(1)最簡單的方法就是保持20行的循環緩衝區,並打印出來當你點擊key(2)在sed或awk中是微不足道的,因爲您可以使用雙地址表單來打印範圍。

因此,讓我們做它在AWK:

#file: extract.awk 

# Initialize the circular buffer 
BEGIN   { count = 0; } 
# When we hit an empty line, clear the circular buffer 
length() == 0 { count = 0; next; } 
# When we hit `key`, print and clear the circular buffer 
index($0, KEY) { for (i = count < 20 ? 0 : count - 20; i < count; ++i) 
        print buf[i % 20]; 
       hi = 0; 
       } 
# While we're between key and limit, print the line 
index($0, KEY),index($0, LIMIT) 
       { print; next; } 
# Otherwise, save the line 
       { buf[count++ % 20] = $0; } 

爲了得到那個工作,我們需要設置的KEYLIMIT值。我們可以做的是在命令行:

awk -v "KEY=4320101" -v "LIMIT=</eventUpdate>" -f extract.awk $FILENAME 

注:

  1. 我以前index($0, foo),而不是更常見的/foo/,因爲它避免了逃脫正則表達式的特殊字符,並有甚至不需要regexen的要求。​​返回needle的索引haystack,索引起始於10如果找不到needle。用作真/假值,找到needle即可。

  2. next導致當前行的處理結束。這個小程序顯示,它可以非常方便。

相關問題