PowerShell : 如何设置输出颜色,Format-Color让黑乎乎的窗口丰富起来

大家好,我是 IT大厨!

眼下的疫情不容小觑。前几天西安的小伙伴开启了核酸检测模式,昨天就轮到生活所在的片区全员检测。所以还是老实呆在家陪家人和学习吧。不管是不是程序员,学习才是王道。

工作原因写过不少脚本,所以把之前对PowerShell中(其它Shell也是类似)输出各种颜色的文字的方法加以总结,并形成成果供大家参考。有不尽之处还望指出,共同成长。

目录

缘起

对Shell的向往

Windows下的PowerShell

使用Write-Host 改变输出颜色

ANSI Color

什么是SGR?

ANSI 转义序列(ANSI Escape Codes)

SGR

如何使用SGR 输出样式

粗体

 斜体

 斜体+粗体

 下划线

 下划线+粗体

 下划线+粗体+斜体

 使用7色设置字体颜色

 使用高亮7色设置字体颜色

 使用高亮7色设置背景色

 使用7色设置背景色

 使用7色同时设置前景色和背景色

 使用7色同时设置前景色和背景色(下划线+粗体+斜体)

 使用256色设置前景/背景色

 使用RGB设置前景和背景色

ColorTool简介

语法

 查看当前设置

获取主题列表

 改变当前主题

使用PowerShell Cmdlet简化样式设置

使用举例

输出日志

格式化表格输出

总结

相关参考:


缘起

对Shell的向往

本人工作以来浸淫Windows多年,虽偶有接触Linux但是大多都是用来学习些东西,加上它炫酷的Shell界面(装X神器)。所以一直对Linux的Shell界面有种莫名的向往。最留恋的莫过于下面的开机画面了。

启动过程中的各种检查日志输出,加上那不一样的绿色状态。就一直觉得很帅。

所以在自己工作中凡事遇到Shell/CMD的地方也总想像它一样在黑黑的屏幕上来点色彩,就像星空中的点点繁星。

Windows下的PowerShell

平时PowerShell用的最多,那么PowerShell是否也有类似的功能呢?其实是有的。

比如: Write-Host这个命令本身就可以设置输出的文字字体颜色和背景颜色。

Write-Host
     [[-Object] <Object>]
     [-NoNewline] #不换行
     [-Separator <Object>] #分隔符 当输入多个字符串的时候可以使用这个选项
     [-ForegroundColor <ConsoleColor>] #字体颜色
     [-BackgroundColor <ConsoleColor>] #字体背景色
     [<CommonParameters>]

那用这个命令能实现Linux下面的效果吗?

答案是可以的。

使用Write-Host 改变输出颜色

在PowerShell中要实现这样的功能可以用下面的几行代码来实现。

$message = "Checking CPU..." #要输出的消息
Write-Host $message.PadRight(50), "[ " -NoNewline #输出前半截,不换行
Write-Host "OK" -ForegroundColor:Green -NoNewline #输出状态,并设置格式
Write-Host " ]" #输出最后的括号并换行

效果如下:

 当然如果每次要输出的时候都这么输肯定会很痛苦,而且要修改输出格式的时候是很不方便的。

那怎么办呢?可以考虑把上面的代码写成一个方法(function)这样每次需要输出类似的代码的时候就调用这个方法就可以了。

方法如下,当然这个里面加入了一些对参数的处理,核心的思想还是上面的三行代码。

function Format-Status {
    param (
        $Message,
        $Status,
        [System.ConsoleColor]
        $ForegroundColor,
        $BackgroundColor,
        [int]
        $Pading = 80
    )
    Write-Host $message.PadRight($Pading), "[ " -NoNewline
    if ($ForegroundColor -and $BackgroundColor) {
        Write-Host $Status -ForegroundColor:$ForegroundColor -NoNewline -BackgroundColor:$BackgroundColor
    }
    elseif ($ForegroundColor) {
        Write-Host $Status -ForegroundColor:$ForegroundColor -NoNewline  
    }
    elseif ($BackgroundColor) {
        Write-Host $Status -NoNewline -BackgroundColor:$BackgroundColor
    }
    else {
        Write-Host $Status -NoNewline 
    }
    
    Write-Host " ]"
}

在控制台里面运行上面的方法之后就可以调用了:

 现在,输出同样的内容只需要调一行代码了

Format-Status -Message $message -Status "OK" -ForegroundColor:Green

 故事到这里似乎也就结束了。

非也非也

PowerShell不仅可以顺序执行命令,也可以异步执行。比如Start-Job和各种带-AsJob的命令都能异步执行。

Start-Job
     [-Name <String>]
     [-ScriptBlock] <ScriptBlock>
     [-Credential <PSCredential>]
     [-Authentication <AuthenticationMechanism>]
     [[-InitializationScript] <ScriptBlock>]
     [-WorkingDirectory <String>]
     [-RunAs32]
     [-PSVersion <Version>]
     [-InputObject <PSObject>]
     [-ArgumentList <Object[]>]
     [<CommonParameters>]

 带-AsJob参数的命令:

Invoke-Command
      [[-Session] <PSSession[]>]
      [-ThrottleLimit <Int32>]
      [-AsJob] #输入这个参数会让该命令以job的方式执行,所以主线程里不会等待执行结束
      [-HideComputerName]
      [-JobName <String>]
      [-FilePath] <String>
      [-RemoteDebug]
      [-InputObject <PSObject>]
      [-ArgumentList <Object[]>]
      [<CommonParameters>]

 那这个又和刚才我们写好的方法有什么关系呢?

我们先对Format-Status稍加修改来模拟真实的执行环境:

function Format-Status {
    param (
        $Message,
        $Status,
        [System.ConsoleColor]
        $ForegroundColor,
        $BackgroundColor,
        [int]
        $Pading = 80
    )
    Write-Host $message.PadRight($Pading) -NoNewline
    Start-Sleep -Milliseconds 100 #在脚本真正执行的时候有时候可能会有延迟
    Write-Host "[ " -NoNewline
    if ($ForegroundColor -and $BackgroundColor) {
        Write-Host $Status -ForegroundColor:$ForegroundColor -NoNewline -BackgroundColor:$BackgroundColor
    }
    elseif ($ForegroundColor) {
        Write-Host $Status -ForegroundColor:$ForegroundColor -NoNewline  
    }
    elseif ($BackgroundColor) {
        Write-Host $Status -NoNewline -BackgroundColor:$BackgroundColor
    }
    else {
        Write-Host $Status -NoNewline 
    }
    
    Write-Host " ]"
}

然后我们再起三个job来模拟真实环境下的多任务执行:

# 0..2 相当于生成一个 @(0,1,2)的数组,这个有点类似于JavaScript的ES6语法
$Jobs = (0..2 | % { 
        Start-Job -ScriptBlock { 
            #为了简单起见,把Format-Status放到Job里面
            #因为每一个Job相当于我们的多线程里面的一个线程
            #它有它自己执行的上下文
            function Format-Status {
                param (
                    $Message,
                    $Status,
                    [System.ConsoleColor]
                    $ForegroundColor,
                    $BackgroundColor,
                    [int]
                    $Pading = 80
                )
                Write-Host $message.PadRight($Pading) -NoNewline
                Start-Sleep -Milliseconds 100
                Write-Host "[ " -NoNewline
                if ($ForegroundColor -and $BackgroundColor) {
                    Write-Host $Status -ForegroundColor:$ForegroundColor -NoNewline -BackgroundColor:$BackgroundColor
                }
                elseif ($ForegroundColor) {
                    Write-Host $Status -ForegroundColor:$ForegroundColor -NoNewline  
                }
                elseif ($BackgroundColor) {
                    Write-Host $Status -NoNewline -BackgroundColor:$BackgroundColor
                }
                else {
                    Write-Host $Status -NoNewline 
                }
        
                Write-Host " ]"
            }
            #Job里面循环21遍模拟实际执行工程中的内容
            0..20 | % {
                #耗时操作
                Start-Sleep -Seconds ( Get-Random -Minimum 0 -Maximum 3)

                $msg = @(
                    "CPU checking ... "
                    "Memory checking ..."
                    "Disk checking ..."
                    "Network checking ..."
                    "BIOS checking ..."
                    "Loading boot image ..."
                )
                $message = $msg[(Get-Random -Minimum 0 -Maximum ($msg.Count - 1))]
                #执行结束输出结果
                Format-Status -Message "[$_]  $message" -Status "OK" -ForegroundColor:Green
            }
        } 
    })
$Jobs | Receive-Job -Wait -AutoRemoveJob #阻塞主线程,接收执行结果,自动销毁job

我们来看下模拟执行的效果:

 一开始还OK,但是慢慢的出现了串行

 为什么呢?因为我们的Format-Status里Write-Host使用了-NoNewline参数,而我们又在前后Write-Host之间设置了延迟,导致线程A刚刚输出不换行的内容之后,线程B又输出了自己的内容就直接接在了线程A输出的内容之后--导致串行。

我想说这并不是我故意这么设置导致输出这样的结果,而是在实际的开发/工作过程中遇到的真实案例。尤其是使用PowerShell执行远程命令并且是以job的形式执行的时候。

那既然如此还有没有更愉快的方法,让PowerShell输出的内容既炫又不会有刚才那样的问题?

答案坑定还是有的,要不我为啥要写这篇blog,O(∩_∩)O哈哈~

ANSI Color

好好的为啥提到ANSI Color?那到底什么又是ANSI Color?

不知道大家有没有注意到我们的PowerShell也好,CMD也好还是Linux也罢都能显示颜色,但是能显示的颜色都只有几种。拿PowerShell或者Windows下面的控制台程序为例:

Black

Blue

Green

Cyan

Red

Magenta

Yellow

White

当然还有个中间灰 Gray,以及与之对应的还有稍微暗一点的Dark系列

DarkBlue

DarkGreen

DarkGray

DarkCyan

DarkRed

DarkMagenta

DarkYellow

PowerShell中的默认颜色

 但是无外乎都是这几种颜色。那么问题来了,谁规定的控制台就这几种颜色呢?在网上一顿研究之后最终目标指向了ANSI Color。

那什么是ANSI Color?

ANSI Color是由美国标准化组织ANSI制定的一系列安全色(ANSI Z535.1-2011),用于安全标识中。比如最常见的就是在消防安全中的各种颜色。终于知道原来各个场所中的各种标识的颜色并不是随便标的,而是有其标准的。下面是其每一种颜色以及其具体的意义:

 哈哈,看了这个是不是对各种标识的颜色有个感性的认识了。计算机最早有显示器的时候也是几乎黑乎乎的一个屏幕,只有文字,能给文字加上颜色就很炫酷了。当然这些文字颜色应该也遵循这样的标准并延续至今(这只是个人猜测,没有考证)。还记得最早老师教各种DOS程序的时候输出的颜色就很有限,那个时候就觉得能输出几种不同的颜色就很激动了。

当然随着计算机软件和硬件的发展,这几种颜色已经远远不能适应大家的需求了。尤其是像Windows这样的图形计算机系统出现以后。但是控制台程序里面还是延续了这几种默认的颜色。不过控制台实际支持的颜色已经不止这几种了。

什么是SGR?

在探讨这个问题之前,大家先思考一下下面的问题。

如果有用过Linux下的vi或者vim工具的大牛应该知晓它们的强大。虽然他们只是款控制台的编辑工具,但是其提供的编辑功能是非常丰富和强大的,尤其是它还是在shell里面工作。这对作为服务器使用没有图形界面的Linux的来说无疑是非常实用的。

那么vi / vim如此强大的功能是如何实现的呢?

ANSI 转义序列(ANSI Escape Codes)

我们先来看下面这张表,这是从别的网站复制过来的。

name

signature

description

A

Cursor Up

(n=1)

Move cursor up by n

B

Cursor Down

(n=1)

Move

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT大厨

技术人,都不易,谢谢大大赏赐

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值