3
votes

Recherche PowerShell dans String et extraire des valeurs spécifiques d'une chaîne

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


1 commentaires

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.


3 Réponses :


1
votes

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")


0 commentaires

0
votes

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


0 commentaires

6
votes

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 ]


6 commentaires

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.