Edytuj: Rozwiązanie na dole tego wpisu.Powershell: Prawidłowe wybarwienie wyjścia Get-Childitem raz na zawsze
Kolorowanie Get-ChildItem (reż lub ls, innymi słowy) nie jest dokładnie to nowy pomysł, ale nie byłem w stanie znaleźć żadnych idealne podejście do kolorowania wyjście w PowerShell. Istnieją dwa ogólne podejścia do pisania funkcji Color-LS:
Przechwytywanie wyjście Get-ChildItem i ponowne wpisywanie tekstu przy użyciu go jako Write-Host z parametrem -ForegroundColor. Takie podejście pozwala na uzyskanie jak największej ziarnistości, ale zmniejsza wydajność Get-Childitem do tekstu. Ponieważ większość użytkowników programu powershell jest świadoma, Get-Childitem nie generuje tekstu, a raczej generuje obiekty. W szczególności lista obiektów FileInfo i DirectoryInfo. Pozwala to na dużą elastyczność w obsłudze danych wyjściowych Get-Childitem.
Wyprowadzanie danych wyjściowych Get-Childitem za pomocą Invoke-Expression do Foreach-Object, zmieniając kolor pierwszego planu konsoli przed wyprowadzeniem każdego obiektu. Coś w rodzaju pełnej, ale lepszej opcji, ponieważ zachowuje typ wyników Get-Childitem.
Oto przykład tej ostatniej metody, dostarczone przez Tim Johnson's Powershell Blog.
Ten kod przypisuje różne kolory w zależności od rozszerzenia pliku, ale w celu rozróżnienia typów plików można zastosować prawie dowolne dane. Powyższy kod wygeneruje następujące wyniki:
To jest prawie idealna, ale jest jedna mała wada: pierwsze wyjście 3 linie (ścieżka do katalogu, nagłówki kolumny, a separatory poziomy) Wciel się w kolor pierwszego elementu na liście. Tim Johnson skomentował na swoim blogu:
Wolałbym, jeśli nagłówek u góry nie zawsze byłby tego samego koloru co pierwszy przedmiot, ale nie potrafię wymyślić tego.
Nie mogę też niestety. Tam wkracza Stack Overflow i jego guru PowerShell: Szukam sposobu na kolorowanie danych wyjściowych Get-Childitem, przy jednoczesnym zachowaniu wyjściowego typu cmdletu, bez zepsucia koloru nagłówka. Zrobiłem eksperymenty i bawiłem się tym podejściem, ale jeszcze nie osiągnąłem żadnego sukcesu, ponieważ pierwsze pojedyncze wywołanie echa wysyła cały nagłówek i pierwszy element.
Wszelkie pytania, uwagi lub nawet lepsze rozwiązania są mile widziane.
Rozwiązanie z podziękowaniem Jon oo i inni, którzy przewidziane pomysły:
Jon Z warunkiem idealne rozwiązanie tego problemu, który mam polerowanego się trochę dopasować schemat w moim oryginalne pytanie. Oto, dla każdego, kto jest zainteresowany. Zauważ, że wymaga to New-CommandWrapper cmdlet z książki kucharskiej Powershell. Cały ten kod trafia do twojego profilu.
function Write-Color-LS
{
param ([string]$color = "white", $file)
Write-host ("{0,-7} {1,25} {2,10} {3}" -f $file.mode, ([String]::Format("{0,10} {1,8}", $file.LastWriteTime.ToString("d"), $file.LastWriteTime.ToString("t"))), $file.length, $file.name) -foregroundcolor $color
}
New-CommandWrapper Out-Default -Process {
$regex_opts = ([System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
$compressed = New-Object System.Text.RegularExpressions.Regex(
'\.(zip|tar|gz|rar|jar|war)$', $regex_opts)
$executable = New-Object System.Text.RegularExpressions.Regex(
'\.(exe|bat|cmd|py|pl|ps1|psm1|vbs|rb|reg)$', $regex_opts)
$text_files = New-Object System.Text.RegularExpressions.Regex(
'\.(txt|cfg|conf|ini|csv|log|xml|java|c|cpp|cs)$', $regex_opts)
if(($_ -is [System.IO.DirectoryInfo]) -or ($_ -is [System.IO.FileInfo]))
{
if(-not ($notfirst))
{
Write-Host
Write-Host " Directory: " -noNewLine
Write-Host " $(pwd)`n" -foregroundcolor "Magenta"
Write-Host "Mode LastWriteTime Length Name"
Write-Host "---- ------------- ------ ----"
$notfirst=$true
}
if ($_ -is [System.IO.DirectoryInfo])
{
Write-Color-LS "Magenta" $_
}
elseif ($compressed.IsMatch($_.Name))
{
Write-Color-LS "DarkGreen" $_
}
elseif ($executable.IsMatch($_.Name))
{
Write-Color-LS "Red" $_
}
elseif ($text_files.IsMatch($_.Name))
{
Write-Color-LS "Yellow" $_
}
else
{
Write-Color-LS "White" $_
}
$_ = $null
}
} -end {
write-host ""
}
To daje wyjście, które wygląda następująco zrzucie:
Jeśli chciałbyś całkowitą linię rozmiar pliku na dole, po prostu dodaj następujący kod:
Remove-Item alias:ls
Set-Alias ls LS-Padded
function LS-Padded
{
param ($dir)
Get-Childitem $dir
Write-Host
getDirSize $dir
}
function getDirSize
{
param ($dir)
$bytes = 0
Get-Childitem $dir | foreach-object {
if ($_ -is [System.IO.FileInfo])
{
$bytes += $_.Length
}
}
if ($bytes -ge 1KB -and $bytes -lt 1MB)
{
Write-Host ("Total Size: " + [Math]::Round(($bytes/1KB), 2) + " KB")
}
elseif ($bytes -ge 1MB -and $bytes -lt 1GB)
{
Write-Host ("Total Size: " + [Math]::Round(($bytes/1MB), 2) + " MB")
}
elseif ($bytes -ge 1GB)
{
Write-Host ("Total Size: " + [Math]::Round(($bytes/1GB), 2) + " GB")
}
else
{
Write-Host ("Total Size: " + $bytes + " bytes")
}
}
Witam. Oto kilka istotnych odnośników: http://stackoverflow.com/a/8088587/539542 – Animesh
Nagłówek i separator nie są wynikiem działania get-childitem. Jest to tylko dodatkowa informacja, gdy wyświetlany jest obiekt systemu plików. Więc prawdopodobnie musisz edytować FileSystem.format.ps1xml ... jeśli to nawet możliwe – Tom
Jon's solution is ideal. Gdy otrzymam wypróbowaną i wypolerowaną nową wersję, umieszczę ją w OP na przyszłość. – Fopedush