2011-09-09 9 views
7

प्रारूप-तालिका का उपयोग करके पावरहेल आउटपुट के लिए केवल कुछ निश्चित शब्द (पूर्ण लाइन नहीं) रंगना संभव है। उदाहरण के लिए, यह स्क्रिप्ट स्ट्रिंग के लिए एक फ़ोल्डर को रिकर्सली स्कैन करती है और फिर प्रारूप-तालिका के साथ परिणाम आउटपुट करती है।पावरहेल स्क्रिप्ट प्रारूप-तालिका आउटपुट में रंग शब्द

dir -r -i *.* | Select-String $args[0] | 
format-table -Property @{label="Line #"; Expression={$_.LineNumber}; width=6}, 
Path, Line -wrap 

यह शब्द हम एक विशिष्ट रंग के साथ की तलाश कर रहे फ़ॉर्मेट करने के लिए इतना है कि आप देख सकते हैं, जहां यह लाइन पर मिला था सक्षम होने के लिए अच्छा होगा।

उत्तर

14

आप तालिका को Out-String में पाइप कर सकते हैं, फिर स्विच के साथ Write-Host का उपयोग करके भागों में स्ट्रिंग लिखें।

कुछ इस तरह:

filter ColorWord { 
    param(
     [string] $word, 
     [string] $color 
    ) 
    $line = $_ 
    $index = $line.IndexOf($word, [System.StringComparison]::InvariantCultureIgnoreCase) 
    while($index -ge 0){ 
     Write-Host $line.Substring(0,$index) -NoNewline 
     Write-Host $line.Substring($index, $word.Length) -NoNewline -ForegroundColor $color 
     $used = $word.Length + $index 
     $remain = $line.Length - $used 
     $line = $line.Substring($used, $remain) 
     $index = $line.IndexOf($word, [System.StringComparison]::InvariantCultureIgnoreCase) 
    } 
    Write-Host $line 
} 

Get-Process| Format-Table| Out-String| ColorWord -word 1 -color magenta 
+2

बढ़िया काम करता है निष्पादित किया जाएगा! संशोधित इस लाइन: $ सूचकांक = $ line.IndexOf ($ शब्द) $ सूचकांक = $ line.IndexOf ($ शब्द, [System.StringComparison] :: InvariantCultureIgnoreCase) – EtienneT

+0

उपेक्षा के मामले पर बात करने के लिए अच्छा। मैंने संशोधन के साथ जवाब अद्यतन किया है। – Rynant

5

मैं Rynant के दृष्टिकोण की तरह। यहाँ एक वैकल्पिक कार्यान्वयन है, IndexOf के बजाय -split का उपयोग कर: अगर लाइन शुरू होता है या दिए गए शब्द के साथ समाप्त होता है, इसलिए अतिरिक्त "नहीं तो पहले" तर्क

filter ColorWord([string]$word, [ConsoleColor]$color) { 
    $later = $false 
    $_ -split [regex]::Escape($word) | foreach { 
     if($later) { Write-Host "$word" -NoNewline -ForegroundColor $color } 
     else { $later = $true } 
     Write-Host $_ -NoNewline 
    } 
    Write-Host 
} 

स्प्लिट रिक्त स्ट्रिंग भी शामिल है।


संपादित करें: Rynant की टिप्पणी के बाद, यहाँ एक और कार्यान्वयन कि दोनों सरल और regex पैटर्न का समर्थन करता है है:

PS> '\d00\d!' | ColorPattern '\d' 'Magenta' -Simple:

filter ColorPattern([string]$Pattern, [ConsoleColor]$Color, [switch]$SimpleMatch) { 
    if($SimpleMatch) { $Pattern = [regex]::Escape($Pattern) } 

    $split = $_ -split $Pattern 
    $found = [regex]::Matches($_, $Pattern, 'IgnoreCase') 
    for($i = 0; $i -lt $split.Count; ++$i) { 
    Write-Host $split[$i] -NoNewline 
    Write-Host $found[$i] -NoNewline -ForegroundColor $Color 
    } 

    Write-Host 
} 

निम्न उदाहरण से उत्पादन अंतर से पता चलता
\d00\d!

PS> '\d00\d!' | ColorPattern '\d' 'Magenta'
\d00\d!

+1

बस सावधान रहें कि आपको रेगेक्स वर्णों से बचने की आवश्यकता है। जैसे '' के $ हे - टिक Tok.mp3 '| ColorWords 'के \ $ ha' लाल'। वैकल्पिक रूप से, '$ _ -split [regex] :: फ़िल्टर में एस्केप ($ शब्द)' का उपयोग किया जा सकता है।जब तक आप रेगेक्स से मेल नहीं करना चाहते, जो अच्छा हो सकता है। – Rynant

+0

@Rynant यह इंगित करने के लिए धन्यवाद! नए संस्करण के साथ अपडेट किया गया। –

1
#$VerbosePreference = 'continue' 
$VerbosePreference = 'silent' 

filter ColorPattern { 
    param ([object]$colors, [switch]$SimpleMatch) 
    [string]$line = $_ 

    $collection = New-Object 'System.Collections.Generic.SortedDictionary[int, pscustomobject]' 
    $RegexOptions = [Text.RegularExpressions.RegexOptions]::IgnoreCase.value__ + [Text.RegularExpressions.RegexOptions]::Singleline.value__ 

    if ($SimpleMatch){ 
     $patternMatches = $colors.keys | % {[regex]::Escape($_)} 
     $reference = 'Value' 
    } else { 
     $patternMatches = $colors.keys 
     $reference = 'Pattern' 
    } 

    # detect RegEx matches and add to collection object 
    Write-Verbose "'$line'" 

    $measureparsing_match = (Measure-Command { 
     foreach ($pattern in $patternMatches){ 
      Write-Verbose "regex pattern: $pattern" 
      foreach ($match in ([regex]::Matches($line, $pattern, $RegexOptions))){ # lazy matching 
       Write-Verbose "`tmatch index: $($match.Index) length: $($match.length)" 

       $currentset = ($match.Index)..($match.Index + $match.length - 1) 
       Write-Verbose "`tcurrent set: $currentset" 

       if (-not [bool]$collection.Count){ 
        Write-Verbose "`t`tindex: $($match.Index) value: $($match.value) (inital add)" 
        [void]$collection.Add($match.Index, [PSCustomObject]@{Length = $match.Length; Value = $match.Value; Pattern = $pattern; Range = $currentset}) 
       } else { 
        (,$collection.Values) | % { 
         $currentRange = $_.range 
         $intersect = Compare-Object -PassThru $currentset $currentRange -IncludeEqual -ExcludeDifferent 
         if ($intersect){ 
          Write-Verbose "`t`tintersect: $([string]($intersect | % {[string]::Concat($_)})) (skipped)" 

          $nonintersect = Compare-Object -PassThru $currentset $intersect 
          Write-Verbose "`t`tnonintersect: $([string]($nonintersect | % {[string]::Concat($_)}))" 

          $nonintersect | % { 
           if ($currentRange -notcontains $_){ 
            Write-Verbose "`t`tindex: $_ value: $($line[$_]) (adding intersect-fallout)" 
            [void]$collection.Add($_, [PSCustomObject]@{Length = $_.Length; Value = $line[$_]; Pattern = $pattern; Range = $currentset}) 
           } else { 
            Write-Verbose "`t`t`tindex: $_ value: $($line[$_]) (skipped intersect-fallout)" 
           } 
          } 
         } else { 
          Write-Verbose "`t`tindex: $($match.index) value: $($match.value) (adding nonintersect)" 
          [void]$collection.Add($match.Index, [PSCustomObject]@{Length = $match.Length; Value = $match.Value; Pattern = $pattern; Range = $currentset}) 
         } 
        } # end values 
       } #end if 
      } # end matching 
     } # end pattern 
    }).TotalMilliseconds 

    $measureparsing_nonmatch = (Measure-Command { 
     if ([bool]$collection.count){ # if there are no matches, skip! 
      Compare-Object -PassThru ` 
      -ReferenceObject (
       $collection.Keys | % { # all matched keys and their lengths 
        $word = $collection.item($_) 
        $currentlength = ($word.value).length 
        ($_..($_ + ($currentlength - 1))) 
       }) ` 
      -DifferenceObject (0..($line.Length - 1)) | # entire line 
       % {[void]$collection.Add($_, [PSCustomObject]@{Length = $_.length; Value = $line[$_]})} # add non matches to collection 
     } 
    }).TotalMilliseconds 

    Write-Verbose "match: $measureparsing_match ms. VS nonmatch: $measureparsing_nonmatch ms." 

    $collection.keys | % { 
     $word = $collection.item($_) 
     if ($word.pattern){ 
      if ($colors.ContainsKey($word.$reference)){ 
       $color = @{ 
        ForegroundColor = $colors[$word.$reference].ForegroundColor; 
        BackgroundColor = $colors[$word.$reference].BackgroundColor 
       } 
       if ($word.value){ 
        Write-Host -NoNewline $([string]::Concat($word.value)) @color 
       } 
      } 
     } else { 
      Write-Host -NoNewline $([string]::Concat($word.value)) 
     } 
    } 
    Write-Host # needed for line feed 
} 

$Patterns = [ordered]@{ 
    # higher in list takes precendence 
    'stopped' = @{ForegroundColor = 'Red'; BackgroundColor='DarkRed'} 
    'running' = @{ForegroundColor = 'Green'; BackgroundColor='DarkGreen'} 
    'paused' = @{ForegroundColor = 'Yellow'; BackgroundColor='DarkYellow'} 
    0 = @{ForegroundColor = 'White'; BackgroundColor='Gray'} 
    '\d+' = @{ForegroundColor = 'Gray'; BackgroundColor='Black'} 
    '\.' = @{ForegroundColor = 'Magenta'; BackgroundColor='DarkMagenta'} 
    '(a|e|i|o|u)' = @{ForegroundColor = 'Yellow'; BackgroundColor='DarkYellow'} 
    '\w+' = @{ForegroundColor = 'Cyan'; BackgroundColor='DarkCyan'} 

} 

# strongly typed collection.. we could probably do this better.. 
$colorCollection = New-Object 'system.collections.generic.dictionary[string, hashtable]'([StringComparer]::OrdinalIgnoreCase) # Ordinal 
$Patterns.GetEnumerator() | % {[void]$colorCollection.Add($_.Name, $_.Value)} 

Get-Service | Out-String -Stream | ColorPattern -colors $colorCollection 
#Get-Service | Out-String -Stream | ColorPattern -colors $colorCollection -SimpleMatch 

उत्तर के लिए देर से की तरह है, लेकिन मैं कई regex समर्थन है, साथ ही सरल मिलान के साथ इस नवीनीकृत किया है। यह पावरहेल v4.0 के तहत परीक्षण किया गया था।

3

मुझे उत्तर @ प्रियंत ने जवाब दिया। मेरे यहां एक संशोधित संस्करण है जिसका उपयोग अरण्यों या शब्दों और रंगों में गुजरकर आउटपुट में एकाधिक शब्दों को रंगने के लिए किया जा सकता है। चाल यह है कि आपको इनपुट टेक्स्ट को न्यूलाइन सेपरेटर के आधार पर लाइनों में विभाजित करना होगा।

filter ColorWord2 { 
param(
    [string[]] $word, 
    [string[]] $color 
) 
$all = $_ 
$lines = ($_ -split '\r\n') 

$lines | % { 
    $line = $_  
    $x = -1 

    $word | % { 
     $x++ 
     $item = $_  

     $index = $line.IndexOf($item, [System.StringComparison]::InvariantCultureIgnoreCase)        
      while($index -ge 0){ 
       Write-Host $line.Substring(0,$index) -NoNewline     
       Write-Host $line.Substring($index, $item.Length) -NoNewline -ForegroundColor $color[$x] 
       $used =$item.Length + $index 
       $remain = $line.Length - $used 
       $line =$line.Substring($used, $remain) 
       $index = $line.IndexOf($item, [System.StringComparison]::InvariantCultureIgnoreCase) 
      } 
     } 

    Write-Host $line 
} } 

और इस प्रकार

Get-Service | Format-Table| Out-String| ColorWord2 -word 'Running','Stopped' -color 'Green','Red' 
+0

मुझे यह जवाब पसंद है, यह वही है जो मैं ढूंढ रहा था। – sch4v4

+0

चीयर्स। मैं वास्तव में इस पर एक भिन्नता का उपयोग करता हूं। दो सरणी में गुजरने के बजाय, मैं सिर्फ एक हैशटेबल में जाता हूं, रंग कुंजी होने के साथ होता है, और मान उन शब्दों की सरणी होती है जिन पर रंग लागू होता है। – stevethethread

+0

@stevethethread \t क्या आप अपना नवीनतम संस्करण साझा कर सकते हैं? –

संबंधित मुद्दे