J'ai un gros fichier qui contient de nombreuses lignes. Par exemple:
$found = $string -match '.*system="(\d+)".*' if ($found) { $system= $matches[1]}
De chaque ligne, je souhaite extraire les informations suivantes:
ts =, system = & something =
, mais le les valeurs après =
changent toujours.
J'ai essayé ceci, mais je n'ai pas réussi à le faire fonctionner:
ts=2019-01-16 network=1.1.1.1 system=irgendwas pid=100 bugReq=dasf something=else maybe=this
3 Réponses :
En supposant que la liste des paires clé-valeur de chaque ligne ne contienne que des valeurs sans espace blanc intégré ni guillemets :
$file = 'file.txt' foreach ($line in [System.IO.File]::ReadLines((Convert-Path $file))) { # ... }
Notez comment j'ai modifié votre exemple de ligne d'entrée légèrement pour changer pid
en pid1
, car PowerShell ne vous permettra pas de créer une variable $ PID
, car il s'agit d'une automatique variable reflétant le PID de la session en cours (ID de processus).
Une autre option (qui éviterait également le conflit de nom de variable) est de créer une table de hachage pour chaque entrée line:
Convertfrom-StringData 'a=b\c' # ERROR: "parsing 'b\c' - Missing control character."
Cette approche a l'avantage supplémentaire de se prêter à collecter les tables de hachage créées pour les lignes individuelles dans un tableau global (par exemple, $ hashTableArray = foreach ($ line in ...) {...}
- mais avec un très gros fichier qui peut ne pas être une option.
En empruntant une idée à la réponse de Lee_Dailey , vous pouvez également utiliser le ConvertFrom- Applet de commande StringData
pour créer la table de hachage, après avoir d'abord placé chaque paire clé-valeur sur sa propre ligne à l'aide de l'opérateur -replace
:
$htValues = ConvertFrom-StringData ($line -replace ' ', "`n")
Donc, à quoi ressemble le journal que vous me montrez, il y a 3 sections à partir desquelles nous pouvons couper et coller Objet, qui peut être retourné à partir d'une nouvelle ligne Keypair, qui peut être retourné à partir d'un espace vide Clé, qui peut être retournée en supprimant =
J'ai écrit une fonction pour ce cas en utilisant cette idée
ts system something -- ------ --------- 2019-01-16 irgendwas else 2019-01-16 irgendwas else 2019-01-16 irgendwas else 2019-01-16 irgendwas else
Cela renverrait
function ConvertTo-PsObjectArrayList($Text,$TextObjectSeparator,$KeyPairSeparator,$KeySeparator){ $ArrayList = New-Object System.Collections.ArrayList $TestData -split $TextObjectSeparator | %{ $PsObject = new-object System.Management.Automation.PSObject $_ -split $KeyPairSeparator | %{ $KeyPair = $_ -split $KeySeparator $PsObject | Add-Member -MemberType NoteProperty -Name $KeyPair[0] -Value $KeyPair[1] } $ArrayList.Add($PsObject) | out-null } return $ArrayList } $TestData = @' ts=2019-01-16 network=1.1.1.1 system=irgendwas pid=100 bugReq=dasf something=else maybe=this ts=2019-01-16 network=1.1.2.1 system=irgendwas pid=130 bugReq=dasf something=else ts=2019-01-16 network=1.1.1.1 system=irgendwas pid=150 bugReq=dasf something=else maybe=this ts=2019-01-16 network=1.1.1.1 system=irgendwas pid=110 bugReq=dasf something=else '@ ConvertTo-PsObjectArrayList -Text $TestData -TextObjectSeparator "`r`n" -KeyPairSeparator " " -KeySeparator "=" | select TS, System, Something
voici une autre solution. [ grin ] il utilise la cmdlet ConvertFrom-StringData
pour analyser l'entrée en objets. puis il crée un [PSCustomObject] avec uniquement les accessoires voulus. enfin, il envoie chaque objet à la collection $ Results.
Bien que la construction de l'objet personnalisé final rend les informations suivantes sans importance dans ce cas, il est important de savoir que la sortie de la cmdlet ConvertFrom-StringData
est une table de hachage standard. cela signifie que l'ordre des objets ne sera presque certainement PAS dans l'ordre d'origine. NE vous attendez PAS à ce que les choses soient dans l'ordre dans lequel elles apparaissent dans la source .
[edit = a ajouté une nouvelle ligne de données avec des espaces intégrés et un modèle -replace
mis à jour pour gérer cela.]
TS System Something -- ------ --------- 2019-01-16 irgendwas else 2019-01-16 PC-001 OtherElse 2019-01-16 PC-666 ThisELse 2019-01-16 PC-123 AnotherElse 2019-01-16 PC-004 Oo-LaLa another value with WhiteSpace Else-ish with Whitespace
sortie à l'écran ...
# fake reading in a text file # in real life, use Get-Content $InStuff = @( 'ts=2019-01-16 network=1.1.1.1 system=irgendwas pid=100 bugReq=dasf something=else maybe=this' 'ts=2019-01-16 network=1.1.1.2 system=PC-001 pid=100 bugReq=dasf something=OtherElse maybe=this' 'ts=2019-01-16 network=1.1.1.66 system=PC-666 pid=100 bugReq=dasf something=ThisELse maybe=this' 'ts=2019-01-16 network=1.1.1.3 system=PC-123 pid=100 bugReq=dasf something=AnotherElse maybe=this' 'ts=2019-01-16 network=1.1.1.4 system=PC-004 Oo-LaLa another value with WhiteSpace id=100 bugReq=dasf something=Else-ish with Whitespace' ) $Results = foreach ($IS_Item in $InStuff) { # this requires that spaces ONLY be found as delimiters # if you have embedded spaces, some sort of data format adjustment will be required # now there is a need for handline embedded whitespace #$IS_Item -replace ' ', [environment]::NewLine | $IS_Item -replace '(\w{1,}=)', ('{0}{1}' -f [environment]::NewLine, '$1') | ConvertFrom-StringData | ForEach-Object { [PSCustomObject]@{ TS = $_.ts System = $_.system Something = $_.something } } } $Results
c'est une bonne collection d'objets simples, donc il sera Export-CSV
tout à fait proprement. [ sourire ]
Bien fait, mais comme pour le piping vers ForEach-Object
avec un [pscustomobject]
cast pour construire des objets personnalisés avec uniquement les propriétés d'intérêt, dans l'ordre (en supposant l'extraction d'une propriété sous-ensemble est vraiment nécessaire): ConvertFrom-StringData | Select-Object ts, système, quelque chose
est non seulement plus concis, mais aussi plus performant.
De plus, bien que ce ne soit pas un problème avec l'exemple d'entrée, il convient de mentionner en général que ConvertFrom-StringData
interprète les caractères \
. comme début de séquences d'échappement de sorte que par exemple, une valeur telle que b \ c
casse la commande: 'a = b \ c' | ConvertFrom-StringData
@ mklement0 - oui, il y a des compromis distincts avec ConvertFrom-StringData
. c'est assez difficile ... et c'est pointilleux d'une manière qui n'est pas immédiatement évidente.
En effet; du côté positif, il est beaucoup plus rapide que l'analyse manuelle de foreach
-loop dans ma réponse.
@Lee_Dailey: Hey Lee merci encore pour votre contribution - je rencontre un nouveau problème dans ce cas! Parfois, dans le fichier journal, il y a des entrées qui dépassent plusieurs lignes, mais chaque nouvelle entrée commence par ts = Comment pouvons-nous gérer cette situation avec votre solution?
veuillez poser une nouvelle question à ce sujet. votre nouveau problème nécessitera probablement une approche différente ... les données d'entrée devront probablement être réorganisées différemment. De plus, le nouvel ensemble de données devra être présenté pour que les gens puissent travailler avec.
jetez un œil à la cmdlet
ConvertFrom-StringData
. si vous remplacez le délimiteur d'espace par des sauts de ligne, l'applet de commande vous donnera une table de hachage qui peut être utilisée pour générer un PSCustomObject. le résultat sera un bel objet propre qui peut être utilisé comme n'importe quel autre. le seul problème est que les propriétés ne seront pas dans un ordre particulier.