2010-07-01 7 views
3

Mon google-fu échoue à nouveau. L'information est (probablement) là-bas, mais je ne peux pas le trouver. Je connais UNIX comme le fond de ma main, j'utilise cygwin etc. mais avec la disponibilité accrue de Powershell sur les serveurs, et (sur les serveurs de production au moins) la difficulté de mettre en place cygwin, j'essaie de prendre Powershell. Si rien d'autre, c'est une autre arme dans mon arsenal.Vous cherchez un équivalent powerhell de la commande awk spécifique

Essentiellement, je suis à la recherche de l'équivalent Powershell de la commande awk:

awk '$9 == "503" { print $0 }' < access_log 

Pour ceux qui ne connaissent pas awk, ce compare essentiellement la zone 9 du fichier d'entrée, puis l'exécution de la block (c'est un journal d'accès apache, donc il me renvoie toutes les lignes d'access_log où le code d'état HTTP retourné est 503). Awk gère la division du fichier en champs basés sur les espaces automatiquement; $ 0 est la ligne entière (non annulée), avec des champs individuels allant dans $ 1, $ 2, ... [etc].

Je sais que je peux utiliser fendu comme ceci:

cat access_log | %{ $_.split() } 

qui divise les lignes entrantes en un tableau, mais je ne peux pas travailler d'ici comment utiliser select-object ou where-object pour sélectionner (et sortie) lignes entières basées sur un champ donné.

L'alternative est select-string mais je ne peux pas sembler voir aucun moyen de passer une expression le long des lignes de %{ $_.split()[8] -eq "503" }. (Je note PowerShell est à base zéro, donc en regardant le champ 8). Je ne suis pas sûr si je manque quelque chose d'évident ici, et je n'ai pas trouvé le bon google-fu pour me donner l'info (donc ne serait pas surpris si c'est un dupe quelque part).

Vive toute aide :-)

+0

Soit dit en passant, que awk de/b 'la awk « $ 9 = = "503" 'access.log'. – jthill

Répondre

3

Ouais, où-objet (? Alias) est mieux dans ce cas:

cat access_log | ?{($_ -split '\s+',0,'regexmatch')[8] -eq 503} 

Notez que la méthode du partage .NET crée des entrées de chaîne vide espaces consécutifs donc j'utilise l'opérateur -split dans PowerShell 2.0 pour éviter cela.

Mon regex est faible dans ce domaine mais j'imagine qu'il est un moyen d'obtenir le champ 9 en utilisant une (approche plus facilement que la mort cérébrale ci-dessous - tout le monde ??) regex:

Mise à jour modèle regex par Johannes 'commentaire:

cat access_log | Select-String '^\s*(?:\w+\s+){8}503' 
+3

'^ \ s * (?: \ W + \ s +) {8} 503' – Joey

+0

Ta pour indiquer que split() ne normalisera pas les espaces consécutifs. Malheureusement, je suis seulement sur PS 1 ... cela pourrait me donner une raison de passer à 2 si. –

+1

Sur PowerShell 1, IIRC, vous pouvez utiliser une autre surcharge de fractionnement, par ex. '' a b'tc ".Split (" 't", [StringSplitOptions] :: RemoveEmptyEntries) ' –

2

a trouvé la réponse - bien que toujours heureux de voir s'il y a d'autres façons de le faire [donc je vais laisser ce sans réponse pendant quelques jours pour voir si quelqu'un d'autre a des méthodes alternatives]. La méthode que j'ai trouvé est:

cat access_log | where-object { $_.split()[8] -eq "503" } 

qui peut être abrégé:

cat access_log | where { $_.split()[8] -eq 503 } 

Il était un cas de faire avancer les choses dans l'ordre. À l'origine, je suivais les bonnes lignes, mais en collant trop de tuyaux sur le chemin.

+2

Vous pouvez utiliser des alias plus courts: 'gc' au lieu de' cat' et '?' Au lieu de 'where' - mais vous ne devriez généralement utiliser que des alias pour une utilisation interactive, pas dans des scripts qui pourraient être déployés sur d'autres ordinateurs. – Joey

0

D'après ce que j'ai compris du code que vous avez posté, vous cherchez à trouver des lignes dont les 9èmes champs sont '503' et ensuite écrire le 1er champ de ces lignes?Si oui:

Get-Content -Path "access_log" | ForEach-Object { 
    if ($_ -match '(?<Field0>\d+)\s(?:\d+\s){7}503') 
    { 
     Write-Host $Matches["Field0"] 
    } 
} 

EDIT:

Un exemple en utilisant Select-String (mieux que mon précédent):

Select-String -Path "access_log" -Pattern '(?<Field0>\d+)\s(?:\d+\s){7}503' | ForEach-Object { 
    Write-Host $_.Matches[0].Groups["Field0"] 
} 
+0

Yikes, je pense que regex est sérieusement exagéré ici. – Joey

+0

Mais merci de poster le motif regex. Je me suis dit qu'il y avait un moyen de spécifier des groupes répétés - vous auriez dû réaliser que ce serait la même chose que pour des choses comme \ d {3}. :-) –

+0

@Keith: Je vous aurais donné l'expression régulière si j'avais suffisamment de rep pour laisser des commentaires :( –