Modifica: Soluzione in fondo a questo post.Powershell: colorazione corretta dell'output Get-Childitem una volta per tutte
Colorare Get-Childitem (dir o ls, in altre parole) non è una nuova idea esattamente, ma non sono stato in grado di individuare eventuali approcci ideali per colorare uscita in PowerShell. Ci sono due approcci generali per la scrittura di funzioni colore-LS:
Intercettare output di Get-ChildItem, e ri-output come testo utilizzando Write-Host con il parametro -foregroundcolor. Questo approccio consente la massima granularità possibile, ma riduce l'output di Get-Childitem al testo. Come molti utenti di PowerShell sono a conoscenza, Get-Childitem non emette il testo, ma emette oggetti. In particolare, un elenco di oggetti FileInfo e DirectoryInfo. Ciò consente una grande flessibilità nella gestione dell'output Get-Childitem.
Eseguire il pipe dell'output di Get-Childitem tramite Invoke-Expression su Foreach-Object, cambiando il colore di primo piano della console prima di emettere ogni oggetto. Una specie di boccone, ma l'opzione migliore perché conserva il tipo di output di Get-Childitem.
Ecco un esempio di quest'ultimo approccio, fornito da Tim Johnson's Powershell Blog.
function color-ls
{
$regex_opts = ([System.Text.RegularExpressions.RegexOptions]::IgnoreCase `
-bor [System.Text.RegularExpressions.RegexOptions]::Compiled)
$fore = $Host.UI.RawUI.ForegroundColor
$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)
Invoke-Expression ("Get-ChildItem $args") | ForEach-Object {
if ($_.GetType().Name -eq 'DirectoryInfo')
{
$Host.UI.RawUI.ForegroundColor = 'Magenta'
echo $_
$Host.UI.RawUI.ForegroundColor = $fore
}
elseif ($compressed.IsMatch($_.Name))
{
$Host.UI.RawUI.ForegroundColor = 'darkgreen'
echo $_
$Host.UI.RawUI.ForegroundColor = $fore
}
elseif ($executable.IsMatch($_.Name))
{
$Host.UI.RawUI.ForegroundColor = 'Red'
echo $_
$Host.UI.RawUI.ForegroundColor = $fore
}
elseif ($text_files.IsMatch($_.Name))
{
$Host.UI.RawUI.ForegroundColor = 'Yellow'
echo $_
$Host.UI.RawUI.ForegroundColor = $fore
}
else
{
echo $_
}
}
}
Questo codice assegna colori differenti basati esclusivamente sulla estensione, ma quasi qualsiasi metrica potrebbe essere sostituito per differenziare i tipi di file. Il codice precedente produce il seguente output:
Questo è quasi perfetto, ma c'è un piccolo difetto: la prima uscita 3 linee (percorso Directory, intestazione colonne, separatori orizzontali) assumere il colore del primo elemento nell'elenco. Tim Johnson ha commentato nel suo blog:
Preferirei se l'intestazione nella parte superiore non fosse sempre dello stesso colore del primo elemento, ma non riesco a pensare in alcun modo a tale proposito.
Né posso, sfortunatamente. Ecco dove arrivano Stack Overflow e i suoi guru PowerShell: sto cercando un modo per colorare l'output di Get-Childitem preservando il tipo di output del cmdlet, senza compromettere il colore dell'intestazione. Ho fatto qualche esperimento e ho giocato con questo approccio, ma non ho ancora avuto alcun successo, dato che la prima singola chiamata echo emette l'intera intestazione e il primo elemento.
Tutte le domande, i commenti o, meglio ancora, le soluzioni sono benvenute.
La soluzione Con grazie a Jon Z e gli altri che hanno fornito idee:
Jon Z fornito la soluzione perfetta a questo problema, che ho ripulito un po 'per abbinare il regime in mia domanda iniziale. Eccolo, per chiunque sia interessato. Si noti che questo richiede New-CommandWrapper cmdlet dal libro di cucina PowerShell. Tutto questo codice va nel tuo profilo.
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 ""
}
Questo produce un output che appare simile al seguente screenshot:
Se si desidera che la linea di totale dimensioni del file in fondo, è sufficiente aggiungere il seguente codice:
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")
}
}
Ciao. Ecco alcuni link rilevanti: http://stackoverflow.com/a/8088587/539542 – Animesh
L'intestazione e il separatore non sono un output di get-childitem. Si tratta solo di informazioni aggiuntive quando viene visualizzato un filesystemobject. Quindi probabilmente dovresti modificare FileSystem.format.ps1xml ... se è anche possibile – Tom
la soluzione di Jon è l'ideale. Una volta scritta una nuova versione ben collaudata e lucidata, la inserirò nell'OP per riferimenti futuri. – Fopedush