2009-11-15 4 views
1

J'essaye d'écrire un script bash pour analyser le fichier journal suivant et me donner une liste des joueurs ACTUELS dans la salle (donc en ignorant les joueurs qui sont partis, mais en incluant les joueurs qui ont peut-être rejoint) . Notez que Samual a rejoint.Analyser les joueurs actuellement dans le lobby

[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 

Pour me donner une liste des joueurs actuellement dans la salle comme ça (je peux probablement utiliser tr pour le commutateur de cas):

'jack','jones','samual' 

Lorsqu'un joueur rejoint il va dire « joueur [Playername | PlayerIP] a rejoint le jeu "(vous pouvez ignorer l'IP Lorsqu'un joueur laisse dira." joueur de suppression [Playername]: Certains RaisonBien que je sache comment obtenir ces deux listes individuellement, j'ai besoin de les combiner pour savoir qui est encore dans la pièce, et l'ordre est important parce qu'ils peuvent rejoindre. Est-ce que quelqu'un peut m'aider avec ça?

J'ai cette déclaration sed pour me donner les joueurs qui ont rejoint:

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

et cela me donne une liste des sortants:

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

Mais ne sais pas comment combiner les deux, ou de mettre les tiques et les virgules dans la liste des joueurs.

Merci

Répondre

3

Une partie de la résolution d'un problème est effectivement choisir l'outil approprié. Dans ce cas, en essayant de le faire tout en bash est probablement pire choix que quelque chose comme Perl ou Python, parce que:

  • il sera plus compliqué à mettre en œuvre, le débogage et maintenir
  • il utilisera beaucoup d'autres processus
  • la performance est susceptible d'être pauvre

Si vous voulez aider à écrire cela dans un langage plus approprié, il suffit de demander.

... plus tard ...

OK, vous avez choisi Perl ....

Vous pouvez certainement faire tout ce que vous essayez de faire dans Perl lui-même. Cependant, comme vous n'êtes pas familier avec cela, j'ai mis en place un petit programme de jouets qui devrait faire ce que vous recherchez.

#!/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"; 
} 

La sortie produit se présente comme suit:

$ ./analyse inputfile 
Jack 
Jones 
Samual 

et que vous souhaitez peut-être appeler quelque chose comme ça de votre script bash:

tail -1000 ghost.log | ./analyse 

ou même:

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

J'ai essayé de garder le Pe programme rl aussi simple que raisonnable. Le seul bit "difficile" est l'expression régulière. Essentiellement, il boucle sur les lignes d'entrée, en essayant de décider si chaque ligne représente quelqu'un qui rejoint ou quitte. Si vous vous connectez, le nom d'utilisateur est ajouté au hachage %present; en partant, il est enlevé. À la fin, les noms sont répertoriés dans l'ordre.

Est-ce suffisant pour vous remettre sur les rails?

+0

Perl fonctionnerait, mais je n'ai aucune expérience avec elle aurait donc besoin de beaucoup d'aide. La forme actuelle du script récupère les 1000 dernières lignes d'un fichier journal actif appelé ghost.log. Ensuite, il trouve le jeu le plus récent que j'ai "Propriétaire" rejoint, et le filtre à juste une liste d'éléments liés à ce nom de famille. Ensuite, je veux une liste de joueurs actuellement dans le jeu que je suis. De là, je dois interroger ma base de données sqlite3 où la liste des noms est l'une des déclarations "where". Dois-je utiliser Perl pour tout cela? Ou est-ce que bash appelle un script perl séparé pour faire l'analyse? Comment ferais-je cela? – Dan

+0

J'ai été capable de lire la plupart de ceci. Je comprends aussi la plupart des regex ... mais qu'est-ce que c'est:? et le :?. Pourquoi la parathèse centrale n'est-elle pas de $ 2, et l'instruction if est-elle vraie pour les lignes qui en contiennent? Que représente le premier (/ et le dernier /)? – Dan

+1

OK, le premier '?:' Fait partie d'une construction '(?: ...)'. Cela fait du clustering plutôt que de la capture. Cela signifie que les contenus sont traités dans leur ensemble, mais ne sont pas affectés à la variable '$ 2'. La raison en est que nous ne nous soucions pas de ce qu'est le contenu, mais nous voulons que le signe '?' Suivant fonctionne sur tout le bloc. Lorsque vous mettez un caractère après?? 'Après ou un seul caractère, cela indique que le groupe ou le caractère est facultatif. Ici nous l'utilisons pour dire que wn adresse IP (la chose dans la construction '(?: ...)') peut être présente ou absente. En outre, le ':?' Plus tard: un deux-points peut ou peut ne pas être présent. – Tim

1

Cela peut fonctionner pour ce que vous voulez. Il suppose, probablement improbable, que si un joueur est listé un nombre impair de fois dans les listes jointes et à gauche combinées qu'il est actuellement dans le jeu (par exemple, join ou join-leave-join) alors qu'un nombre pair d'entrées indique qu'il a quitté (par exemple, joindre-congé).

#!/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 "'" 

Résultat de votre exemple des données:

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

vous pouvez utiliser reluquer

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 

sortie

./shell.sh 
Jones 
Samual 
Jack 
Questions connexes