2016-04-14 92 views
0

我使用awk來匹配日誌文件中的特定行。根據它匹配的線我想使用不同的FS。我想要做一些類似於下面的內容但不起作用的東西。可能嗎?Awk - 每個匹配行的不同FS

#!/usr/bin/gawk -f 
if ($0 ~ "good.morning") 
{ FS=","; print $1 } 
if ($0 ~ "good.evening") 
{ FS=";"; print $2 } 

我意識到我可以在腳本的{BEGIN}部分設置FS。或者我可以在調用腳本時設置FS。但我希望能夠更好地控制每個匹配記錄的FS。

回答

2

是的,你可以做到這一點通過以下方式:

$ cat data 
ONE 1 I 
TWO 2 II 

THREE:3:III 
FOUR:4:IV 
FIVE:5:V 

SIX 6 VI 
SEVEN 7 VII 

$ ./awkscript data 
I 
II 

III 
IV 
V 

VI 
VII 
$ 

awkscript如下:

#!/bin/awk -f 
{ 
    if ($0 ~ /:/) 
    { 
     FS=":"; 
     $0=$0 
    } 
    else 
    { 
     FS=" "; 
     $0=$0 
    } 
    #print the third field, whatever format 
    print $3 
} 

$0=$0根據當前FS重新評估領域。

2

你的問題則存在FS通常用作它讀過的線分成場awk的基本流程是:

  • 執行預讀命令。
  • 對於每一行:
    • 將行隔離爲字段。
    • 執行基於行的命令。
  • 執行讀後命令。

你可以看到,與成績單:

pax> (echo '1 2 3'; echo '4;5;6') >inputdata 
pax> awk '{FS=";"; print $2} inputdata 
2 
5 

1 2 3線被分成主體運行前場,所以FS的設置只會影響後續行。

所以,是的,你可以改變在線路電平的字段分隔符,但它通常有許多工作要做之前該行已讀(比如在以前線的處理)。

但是,有一個稍微有點棘手的方法來實際強制awk重新解析該行,只需設置它等於自己。首先,我們改變線路輸入使用;作爲一個字段分隔符:

pax> (echo '1;2;3'; echo '4;5;6') >inputdata 

在我們運行您最初以爲可能工作腳本風格:

pax> awk '{FS=";"; print $2}' inputdata 

5 

正如你可以看到那第一個例子,行1;2;3被放到一個字段中,因爲白色空間被用作分隔符。因此第二場是空白的。對比,與:

pax> awk '{FS=";"; $0 = $0; print $2}' inputdata 
2 
5 

$0 = $0添加到改變FS可變後混合引起awk重新解析使用修改的分離器的線路,並且因此重新填充$1$2等。

1

由於FS必須設置爲Awk讀取行之前所需的值,最簡單的解決方法可能是明確地用split代替。

#!/usr/bin/gawk -f 
/good.morning/ { split($0,a,","); print a[1] } 
/good.evening/ { split($0,a,";"); print a[2] } 

(我猜你真的是good\.morning等,但從來不介意我。)

+0

NVM是一個我沒有聽說過之前,因此它可能是更好的拼寫出完整的。特別是因爲其中一個定義(http://www.urbandictionary.com/define.php?term=nvm)指出「你太愚蠢了,不明白我在說什麼,所以我放棄了」,我假設你不會不想冒犯OP的危險:-) – paxdiablo