2009-11-15 46 views
1

我正在嘗試編寫一個bash腳本來解析出以下日誌文​​件,並給我一個當前玩家在房間中的列表(因此忽略了剩下的玩家,但包括可能已經重新加入的玩家) 。請注意,Samual已經重新加入。解析當前在大廳的玩家

[Sun Nov 15 14:12:50 2009] [GAME: Tower Defense Join Fast!] player [Samual|192.168.1.115] joined the game 
[Sun Nov 15 14:12:54 2009] [GAME: Tower Defense Join Fast!] deleting player [Samual]: has left the game voluntarily 
[Sun Nov 15 14:12:57 2009] [GAME: Tower Defense Join Fast!] player [Jack|192.168.1.121] joined the game 
[Sun Nov 15 14:13:04 2009] [GAME: Tower Defense Join Fast!] player [NoobLand|192.168.1.153] is trying to join the game but is banned by IP address 
[Sun Nov 15 14:13:04 2009] [GAME: Tower Defense Join Fast!] [Local]: User [NoobLand] was banned on server [www.example.com] on 2009-11-04 by [Owner] because []. 
[Sun Nov 15 14:13:13 2009] [GAME: Tower Defense Join Fast!] player [Jones|192.168.1.178] joined the game 
[Sun Nov 15 14:13:21 2009] [GAME: Tower Defense Join Fast!] player [Arnold|192.168.1.126] joined the game 
[Sun Nov 15 14:13:35 2009] [GAME: Tower Defense Join Fast!] [Local]: Autokicking player [Arnold] for excessive ping of 131. 
[Sun Nov 15 14:13:35 2009] [GAME: Tower Defense Join Fast!] deleting player [Arnold]: was autokicked for excessive ping of 131 
[Sun Nov 15 14:13:44 2009] [GAME: Tower Defense Join Fast!] [Lobby] [Jones]: !chekme 
[Sun Nov 15 14:13:44 2009] [GAME: Tower Defense Join Fast!] non-spoofchecked user [Jones] sent command [chekme] with payload [] 
[Sun Nov 15 14:13:45 2009] [GAME: Tower Defense Join Fast!] [Local]: Waiting for 4 more players before the game will automatically start. 
[Sun Nov 15 14:14:05 2009] [GAME: Tower Defense Join Fast!] player [Samual|192.168.1.116] joined the game 

給我的球員名單目前在房間裏像這樣(我大概可以使用的情況下開關TR):

'jack','jones','samual' 

當玩家加入,它會說「播放器[Playername | PlayerIP]加入了遊戲 「(你可以忽略IP 有玩家離開時,它會說。」 刪除播放器[Playername]:某種原因

雖然我知道如何分別獲得這兩個列表,但我需要將它們結合起來,以便弄清楚誰仍在房間中,而順序很重要,因爲他們可以重新加入。誰能幫我這個?

我有這個sed的說法,給我誰也加入了玩家:

sed -n 's/\[.*\] \[GAME: .*\] player \[\(.*\)|.*\] joined the game/\1/p` 

,這給我的畢業生名單:

sed -n 's/\[.*\] \[GAME: .*\] deleting player \[\(.*\)\].*/\1/p' 

但不知道如何結合這兩個,或者把蜱和逗號放在玩家名單中。

謝謝

回答

3

有效地解決問題的一部分是選擇正確的工具。在這種情況下,試圖做到這一切在bash,可能比像Perl或Python更糟糕的選擇,因爲:

  • 將更加複雜,實施,調試和維護
  • 它會使用更多的處理
  • 表現可能較差

如果你想幫助以更合適的語言寫這篇文章,只是問。

...稍後...

好的,您選擇了Perl ...。

你當然可以做任何你想在Perl本身做的事情。然而,由於你不熟悉它,我已經制定了一個小玩具程序,它應該可以做你以後的事情。

#!/usr/bin/perl -w 

use strict; 

my %present; 

while (<>) { # loop over input lines 
    if (/player \[(.*?)(?:\|\d+\.\d+\.\d+\.\d+)?\]:? (.*)/) { 
    my $player = $1; 
    my $event = $2; 

    if ($event eq "joined the game") { 
     $present{$player} = 1; 
    } elsif ($event eq "has left the game voluntarily") { 
     delete $present{$player}; 
    } elsif ($event =~ /^was autokicked/) { 
     delete $present{$player}; 
    } 
    } 
} 

foreach (sort keys %present) { 
    print "$_\n"; 
} 

輸出產生這個樣子的:

$ ./analyse inputfile 
Jack 
Jones 
Samual 

,你不妨把它從你的bash腳本是這樣的:

tail -1000 ghost.log | ./analyse 

甚至:

playerspresent=`tail -1000 ghost.log | ./analyse` 

我試過讓Pe rl程序儘可能簡單明瞭。唯一的「難點」是正則表達式。本質上,它循環輸入各行,試圖決定每行是否代表某人加入或離開。如果加入,用戶名將被添加到%present散列;如果離開,它將被刪除。最後,名稱按順序列出。

這足以讓你回到正軌嗎?

+0

的Perl的工作,但我沒有任何經驗因此需要很多幫助。腳本的當前形式抓取名爲ghost.log的最近1000行活動日誌文件。然後找到我「所有者」加入的最新遊戲,並將其過濾爲與該遊戲名稱相關的項目列表。然後,我想要一個當前在遊戲中的玩家列表,而不是我所處的列表。從那裏我需要查詢我的sqlite3數據庫,其中名稱列表是「where」語句之一。我應該用perl來做這些嗎?或者讓bash調用一個單獨的perl腳本來進行解析?我將如何做到這一點? – Dan 2009-11-15 22:30:02

+0

我已經閱讀了大部分內容。我也理解大多數正則表達式...但是:什麼是:?和:?。爲什麼中間語言不是2美元,if語句對於包含該語句的行是否正確?第一個(和最後一個/)代表什麼? – Dan 2009-11-16 19:40:31

+1

好的,第一個'?:'是'(?:...)'結構的一部分。這是集羣化,而不是捕獲。這意味着內容被視爲一個整體,但不會被分配到$ 2變量。原因是我們不在乎內容是什麼,但我們確實希望在整個塊上運行以下'?'符號。當你在組或單個字符後面加上一個'?'時,說組或字符是可選的。這裏我們用它來說明IP地址('(?:...)'結構中的東西)可以存在或不存在。此外,後面的':?':冒號可能存在​​也可能不存在。 – Tim 2009-11-16 20:29:23

1

這可能適用於你想要的。它可能會不安全地假設,如果玩家在合併加入和左側列表中列出了他目前正在遊戲中的奇數次(例如加入或加入 - 離開加入),而偶數條目表明他已經離開(例如加入離開)。從您的示例數據

#!/bin/bash 
joined=$(sed -n 's/\[.*\] \[GAME: .*\] player \[\(.*\)|.*\] joined the game/\1/p' gamefile.txt) 

left=$(sed -n 's/\[.*\] \[GAME: .*\] deleting player \[\(.*\)\].*/\1/p' gamefile.txt) 

saveIFS="$IFS" 
IFS=$'\n' 
players=("$(echo -e "$joined\n$left" | sort | uniq -c)") 
IFS="$saveIFS" 

flag=0 
echo -n "'" 
for i in "${players[@]}" 
do 
    if [[ $flag == 1 ]] 
    then 
     echo -n "', '" 
    fi 
    j=($i) 
    if ((${j[0]}%2 == 1)) 
    then 
     flag=1 
     echo -n "${j[1]}" 
    fi 
done 
echo "'" 

結果:

'Jack', 'Jones', 'Samual' 
1

可以使用呆子

awk '$11=="player" && ($(NF-2)=="joined" || $12=="[Lobby]") { 
gsub(/\[|\|.*\]|:/,"",$12) ; player[$12] 
} 
$11=="deleting"{gsub(/\[|\]|:/,"",$13); delete player[$13] } 
END{ 
for(i in player){ print i } 
}' file 

輸出

./shell.sh 
Jones 
Samual 
Jack