配置Windows下的终端与Shell

 

在Microsoft Build 2019上微软发布了Windows Terminal,在2019年6月中旬,微软正式在应用商店上架了Windows Terminal的Preview版本,趁此机会配置一下Windows下的终端和shell

在Microsoft Build 2019上微软发布了Windows Terminal,在2019年6月中旬,微软正式在应用商店上架了Windows Terminal的Preview版本,趁此机会配置一下Windows下的终端和shell

终端与Shell

这里需要了解一下终端 terminal和 shell 的区别: 在命令行中,shell 提供了访问操作系统内核功能的途径,比如说我们所熟悉的 bash、zsh,都是不同的 shell;而终端则为 shell 提供视觉界面(窗口),比如我们所熟悉的 iTerm2、Linux 桌面上的终端工具等。甚至于我们在 VSCode 中所使用的命令行,也是某种意义上的终端。 我们在 Windows 下所使用的 CMD、Powershell 既然是一个终端,也是一个 Shell,还是同名的脚本系统。

所以Windows Termianl只是一个终端而已,而没有提供一个更加好用的Shell,改善体验的话两个部分都需要配置

对于终端,Windows下最常用的:

  • CMD的黑色背景的终端
  • Powershell的蓝色背景的终端
  • WSL的默认Bash终端

相比于其他“现代终端软件”如Cmder在美观和易用性上都显得非常落后,Cmder是一个Console Emulator,对这个概念个人的理解是这样的:

在图形化界面出现之前,与Unix系统交互的唯一方式就是借助Shell所提供的文本命令行界面(Command Line Interface,CLI),而日常用的操作系统都配备了图形化界面,如一些Linux发行版进入CLI的一种方法是退出图形化界面,进入文本模式,也就是显示器上只有shell CLI,这种方式就叫做Linux控制台(Linux Console),而Linux系统启动后又会创建出多个虚拟控制台(TTY)方便使用;而另外一种方式也就是在图形化界面打开图形化的终端窗口连接到TTY,也就是终端仿真器(Console Emulator)。

Cmder不仅仅解决了Windows下终端的美观性问题还支持部分Linux命令(cmd模式下区分于Powershell自带的别名)使得shell的体验更好

然而cmder并没有真正的集成到系统中去,比如说Git依然需要单独安装,某些命令和cmder内建的指令存在冲突,尽管使用Scoop解决了部分安装软件和配置环境变量的问题,系统自带终端和Shell依然是不好用

因为个人一直觉得能用自带的就不用第三方,所以就往配置方面查了一些东西,发现主要是以下几个问题:

  • 终端代码页不支持大部分的字体,如Consola
  • 终端的配色、主题自定义相对不便
  • Powershell用不习惯
  • 缺少顺手的命令行工具

下面就来一个个的解决

修改字体

默认的Powershell终端窗口是无法使用Consola字体的,考虑到偶尔还是要用的,所以可以在运行的时候输入chcp 65001使代码页用UTF8进行编码,而在新版本的Win10中,在“控制面板-时钟和区域-区域-管理-更改系统区域设置”可以打开系统编码默认为UTF8的设置,看了下评论,现阶段还是可能存在一些问题,我暂时没有遇到,另外还有其他的字体可以不依赖于此使用:

Microsoft YaHei Mono on GitHub 微软为 WSL/Bash on Ubuntu on Windows 设计的字体,PowerShell 和 cmd也能用效果相当于微软雅黑和 Consolas 的混搭

更详细的可以参考:自定义 Windows PowerShell 和 cmd 的字体

Pshazz扩展

作者在其Github项目页面:lukesampson/pshazz介绍如下:

给你的powershell一些pizazz,Pshazz扩展了您的Powershell配置文件通过添加:

  • 一个更好的提示,包括Git和Mercurial信息
  • Git和Mercurial标签完成
  • 一个SSH帮助程序,可让您再也不输入私钥密码
  • 明智的别名,以及添加自己的别名和删除不喜欢的别名的简单方法

主要还是主题,可以在~\scoop\apps\pshazz\current\themes目录下修改或者创建主题配置文件,下面是参考自带主题和Wiki修改的,添加了Conda环境的显示(使用文末的方法添加的Conda环境变量),pshazz use THEME_NAME.json即可应用主题

{
    "plugins": [ "git", "ssh", "z", "virtualenv" ],
    "prompt": [
        [ "green",  "", " $path" ],
        [ "white",   "", "$(if ($git_branch) {' on git:'} else {':'})" ],
        [ "cyan",    "", "$git_branch" ],
        [ "red",   "", " $git_local_state" ],
        [ "white",   "", " $git_remote_state" ],
        [ "",        "", " [$([datetime]::now.tostring(\"HH:mm:ss\"))]" ],
        [ "darkgreen", "", " $Env:CONDA_DEFAULT_ENV "],
        [ "white", "", "`n`$" ]
    ],
    "git": {
        "prompt_unstaged": "*",
        "prompt_staged": "+",
        "prompt_stash": "$",
        "prompt_untracked": "%",
        "prompt_remote_push": ">",
        "prompt_remote_pull": "<",
        "prompt_remote_same": "="
    }
}

这个作者同时也开发了Windows下的包管理软件scoop,在我之前的文章中有介绍,网上搜一下也有其他人写的配置文章;另外一个就是自定义配色的问题了,依然使用这个作者开发的工具

Concfg修改配色

先贴上Github项目链接:lukesampson/concfg

concfg 是一个实用程序,用于导入和导出Windows控制台设置,如字体和颜色,这里主要是更改一下颜色的映射关系,因为最后呈现的效果也取决于终端,所以还是时不时还是需要细调(建议给编辑器装些色彩方面的插件),配置文件路径~\scoop\apps\concfg\current\presets

{
    "cursor_size":  "small",
    "command_history_length":  50,
    "num_history_buffers":  4,
    "command_history_no_duplication":  false,
    "quick_edit":  true,
    "insert_mode":  true,
    "load_console_IME":  true,
    "font_face":  "Consolas",
    "font_true_type":  true,
    "font_size":  "0x18",
    "font_weight":  0,
    "screen_buffer_size":  "80x3000",
    "window_size":  "80x20",
    "fullscreen":  false,
    "popup_colors":  "cyan,white",
    "screen_colors":  "white,black",
    "black":  "#1E1E1E",
    "dark_blue":  "#2472C8",
    "dark_green":  "#0DBC79",
    "dark_cyan":  "#11A8CD",
    "dark_red":  "#CD3131",
    "dark_magenta":  "#BC3FBC",
    "dark_yellow":  "#E5E510",
    "gray":  "#E5E5E5",
    "dark_gray":  "#666666",
    "blue":  "#3B8EEA",
    "green":  "#23D18B",
    "cyan":  "#29B8DB",
    "red":  "#F14C4C",
    "magenta":  "#D670D6",
    "yellow":  "#F5F543",
    "white":  "#E5E5E5"
}

Windows Terminal

首先需要注意的现在还是pre-realses状态的软件,可靠性不好说(偶尔比较稳,偶尔复制个文本就闪退了,10月之后还可以,因为自动更新的存在,稳定性随缘),不推荐作为处理重要任务的工具;本文会更新的Windows Terminal的部分动态和配置文件以方便上手

动态

每次大版本更新的feature可以参考开发博客,下面罗列下历史(之前截的图)

  • Microsoft Build 2019期间发布,Github开源Introducing Windows Terminal,可以自行编译使用(默认设置和宣传图相差甚远,所以就有了这篇文章)

▲发布后的第一个版本的默认的设置(1903的浅色模式下) ▲修改设置后 ▲宣传图

  • 在2019年6月中旬,微软正式在应用商店上架了Windows Terminal的Preview版本,现阶段只有Json的方式做配置(看VSCode的情况,基本上一直只有Json了)
  • 九月份以来的0.4.2382.0版本的稳定性堪忧,日常奔溃,经常需要电脑重启才可以解决(可能杀掉后台进程就好了吧)
  • 九月底,Windows Terminal迎来大更新,导致本文之前的配置文件的格式变得不可用,0.5.2661.0的Release Note写到:

    There’s a settings schema! If you’re using VS Code, it can help you not write typos. (#2803) 也就是说使用VSCode才能获得设置的提示,这点和VSCode的JSON配置方式是一样的,在填写JSON的时候有提示和默认值

  • 11月底,迎来了0.7更新,带来了分屏(之前的DEMO用的tmux),可拖动的标签,更美观的边框(窄边框),终端内默认支持中文输入

边框问题在Github上早就有issue了,之前不得不使用深色的背景和较低的透明度来掩盖这个问题,对比如下

需要在系统设置的个性化中开启“标题栏和窗口边框”(如果不开启就默认为白色)

至于分屏,很多终端软件都有,添加分屏窗口时打开的是默认的shell

The following key bindings are included by default within this release to invoke panes actions:

{ "command": "splitHorizontal", "keys": [ "alt+shift+-" ] },
{ "command": "splitVertical", "keys": [ "alt+shift+plus" ] },
{ "command": { "action": "moveFocus", "direction":"down" }, "keys": [ "alt+down" ] },
{ "command": { "action": "moveFocus", "direction":"left" }, "keys": [ "alt+left" ] },
{ "command": { "action": "moveFocus", "direction":"right" }, "keys": [ "alt+right" ] },
{ "command": { "action": "moveFocus", "direction":"up" }, "keys": [ "alt+up" ] },
{ "command": { "action": "resizePane", "direction":"down" }, "keys": [ "alt+shift+down" ] },
{ "command": { "action": "resizePane", "direction":"left" }, "keys": [ "alt+shift+left" ] },
{ "command": { "action": "resizePane", "direction":"right" }, "keys": [ "alt+shift+right" ] },
{ "command": { "action": "resizePane", "direction":"up" }, "keys": [ "alt+shift+up" ] },

我也不清楚编译菜单的横纹是是什么情况…

安装

仅支持1903以上的Win10,主要的安装方式是微软的应用商店(方便自动更新),如果搜索不到的话需要把地区更改为中国以外的地区(如美国,同时也会发现Win10多了很多东西)再搜索

还可以到Github的Realses Page下载安装包

另外在Scoop的dorado仓库中做了收录,添加仓库后安装即可(方法见后文)

Profile参考

具体的配置选项可以参考Github仓库下的文档:Profiles.json Documentation

0.5.2661.0版本更新之后,之前默认的配色方案和快捷键不再出现在主配置文件中,profile文件负责自定义标签,配色和快捷键,更新之后把之前自定义的部分复制过来就好,就默认的配置文件来说,需要调节的部分不多即可达到最初的宣传图的效果,考虑到刚刚上手配置起来有些繁琐,可以参考之前的配置做些必要的修改:

\\开启背景透明(亚克力透明)
"useAcrylic" : true
\\透明度
"acrylicOpacity" : 0.75
\\背景图片
"backgroundImage": "PATH_TO_IMG"
\\配色方案,内置了One Half Dark/Light、Campell、Solarize
"colorScheme": "One Half Dark"
\\图标
"icon" : "C:\\Users\\lwz32\\Pictures\\openwrt.ico",

另外修改启动目录时(比如设定为wsl的~),如果使用wsl -d debian会无效,直接使用debian即可,参考自Windows Terminal 的 WSL 配置

除了常见的命令行环境还有其他的工具也可以使用,只需要修改json中的commandline项为需要运行的命令即可(guid不能出现重复,稍微修改下就好)

便捷地使用SSH

在版本较新的Windows 10中已经内置了OpenSSH,可以用SSH和SCP,如果搭配上私钥登陆认证以及Terminal添加新建窗口的自定义命令,可以免去平时一些繁琐的SSH操作

生成密钥,默认暂时是RSA-2048bit

ssh-keygen

之后会提示输入密钥的保存路径,如果是初次设置默认就好,否则会覆盖掉之前的文件

 ~: [00:42:02]
$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (C:\Users\USER/.ssh/id_rsa):

完成后会在指定的目录生成指定文件名的两个文件:私钥id_rsa和公钥id_rsa.pub,公钥保存在ssh-server中就好,Ubuntu和Debian默认在/root/.ssh/authorized_keys文件中,把公钥的文件内容复制进去就好

之后在Terminal中添加标签,在profiles下添加一项(主要修改commandline、name,GUID只要不和已有的重复就行):

{
    "guid": "{61c54bbd-c2c6-5271-96e7-0f9a87ff44bf}",
    "name": "OpenWrt",
    "background": "#000000",
    "useAcrylic": true,
    "acrylicOpacity": 0.7,
    "commandline": "ssh root@192.168.1.1",
    "colorScheme": "One Half Dark",
    "icon" : "C:\\Users\\*\\Pictures\\openwrt.ico",
    "fontSize": 11
}

Powershell

偶尔不得不用,如果要常用Powershell处理文件的重定向,强烈建议看下本文后面的一节:Powershell与bash的重定向的差异

获取插件

Powershell Gallery中也有类似的插件,因为体系不同就不详细介绍了

使用Conda环境

cmder这方面做的非常省事,而bash会有conda init,但是Powershell还是需要些额外的工作

Anaconda安装过程中添加环境变量后,Powershell可以运行Conda命令,但是无法激活Conda环境,需要做些额外的工作,参考:BCSharp/PSCondaEnvs解决Win10 PowerShell无法激活Anaconda环境的问题

对于4.6之后的版本,实践的过程,和第二篇文章有点不一样,依然需要管理员模式下运行三步

conda install -n root -c pscondaenvs pscondaenvs
Set-ExecutionPolicy RemoteSigned
conda init powershell

自带的别名

PowerShell设置命令别名Alias一文中有介绍Powershell的别名设置情况

通过Get-Alias可以看到其实默认可用的别名和Linux系统差不多了,相对CMD的一大优势,只是支持的Powershell的内建命令

 ~: [01:12:12] 
 $ Get-Alias                                                                                                                                                                      

别名解决了相当一部分的命令的便利性问题,但是有些场景还是有些尴尬的,比如说统计字符数,最短的方式是这样

 ~: [01:22:58]
$ cat C:\Users\lwz32/.ssh/id_rsa | measure -c -l -w

Lines Words Characters Property
----- ----- ---------- --------
   27    33       1648

这个可以使用参考文章中的更改带参数的别名解决,但是还是有些麻烦,还不如直接使用WSL的wc

 ~: [01:23:35]
$ cat C:\Users\lwz32/.ssh/id_rsa | wsl wc
     27      33    1702

如果想要相对自由的设置别名的话可以使用下文中的scoop

Scoop

安装命令行工具

以博客中介绍Scoop的文章为主,这里就摘取和本文主题相关的部分

默认的main仓库以命令行工具为主(比如收录的cmder是个有GUI的终端软件),例如Linux常用的sed, grep, gawk,vim可以大大方便Powershell的日常使用,需要注意的是如果Scoop安装的软件和Powershell的命令或者别名重合,Powershell的命令依然被优先使用(例如wget)

除去上面介绍的一些,其实想得到命令行工具都可以在Scoop中使用scoop search找下看看

$ scoop list
Installed apps:

  7zip 19.00
  chromedriver 76.0.3809.126
  cmder-full 1.3.11
  concfg 0.2019.03.09
  ffmpeg 4.1.3 #编码工具
  gawk 3.1.7
  gcc 8.1.0
  gdrive 
  git 2.21.0.windows.1
  grep 2.5.4
  innounp 0.48
  iperf3 3.1.3 #网速测试工具
  nodejs 12.5.0
  pshazz 0.2019.04.02
  R 3.6.0
  sed 4.2.1
  tesseract 4.1.0.20190314 #OCR工具
  vim 8.1.1302 
  youtube-dl 2019.05.20 #偶尔下载视频
  trafficmonitor #任务栏网速,CPU内存占用监测
  screentogif #Gif录屏软件

Scoop别名

Powershell的别名设置不方便,直接使用WSL的自定义别名(.bashrc)调用Windows下的程序又不能直接在Powershell中运行,直到发现Scoop可以自由的添加“环境变量”,想起来Scoop alias来设置程序运行的scoop别名

本来的用法应该是为Scoop内的操作添加别名:

# Install app
scoop alias add i 'scoop install $args[0]' 'Innstall app'
scoop alias add add 'scoop install $args[0]' 'Install app'

# Uninstall app
scoop alias add rm 'scoop uninstall $args[0]' 'Uninstall an app'
scoop alias add remove 'scoop uninstall $args[0]' 'Uninstall an app'

# List apps
scoop alias add ls 'scoop list' 'List installed apps'

# Update
scoop alias add u 'scoop update $args[0]' 'Update apps, or Scoop itself'
scoop alias add upgrade 'scoop update $args[0]' 'Update apps, or Scoop itself'

但是这个格式看起来就很自由:

比如说给WinMTRCmd添加一个scoop mtr的别名

scoop alias add mtr '~/winMTRCmd $args[0]' 'MTR tools for Win CMD'

之后使用scoop mtr HOSTNAME就可以愉快的使用mtr工具了

Powershell与bash的重定向的差异

探索这个问题的背景是:XDR6088刷OpenWrt:Powershell下使用nc命令重定向的备份大小异常

在Windows下使用nc导出路由器备份的mtdblock的时候,Windows上一定要用CMD运行nc并重定向nc -l -p 9995 > backup.img),不能用Powershell(备份传输完成后,校验的话就会发现用Powershell运行同样的命令会得到不一样的文件),因为这一条操作失误导致我刷OpenWrt后刷回原厂系统的过程中导致变砖

类似的问题:在Powershell使用docker命令保存镜像,用重定向符有问题,不能直接复制linux bash的命令

问题的简化与复现

可以尝试构建一个二进制文件:原文件.img,用Powershell的重定向输出了一个新文件(参考cat 原文件.img > 新文件.img,对比大小就能发现重定向输出的文件与源文件不一样,这就是要解决的问题:需是在原文件丢失的情况下,使用新文件还原出原文件

如果用cmd执行相同的命令的话就没有这个问题,下面继续探索

对比文件的差异

首先我用16进制的编辑器打开文件,做字段的对比,每一行12个十六进制的pair(这里将形如FF的2个十六进制数的缩写称为1个pair)

FF FE 55 00 42 00 49 00 23 00 01 00
00 00 00 00 00 00 00 00 00 00 00 00 # 12个00
00 00 00 00 00 00 00 00 01          # 8个00

      55 42 49 23 01
00 00 00 00 00 00 00 00 00 00       # 10个00,下面一行省略

                         01

看起来是在每个16进制pair字符后都加了00,这里想起了windows的文件编码差异,即Powershell使用CRLF UTF-16 LE BOM而CMD命令行使用的LF ANSI,通过NotePad++打开,发现新文件是UTF-16 BOM编码的,原文件是ANSI(普通二进制文件),就常规的文本文件而言,解决的办法就是在NotePad++中选择重新编码保存,然而在这个问题上不管用

关于windows下的各种编码,可以参考Unicode 编码及 UTF-32, UTF-16 和 UTF-8

重编码+dos2unix之后,用16进制的编辑器打开文件对比,还是有个别位的值不一样(最主要的是文件大小都不一样)

编码问题 or Powershell的机制问题

对此也和同学进行了探讨,焦点在于文本编码往往有明确的 二进制 到 字符 的一一映射关系,如果考虑将二进制文件使用文本编码来编解码的话,存在部分二进制没有相应的字符对应

在编码的范围内搜索了很久没有找到答案后,目光转向Powershell本身应该如何避免出现输出非二进制数据的文件How to pipe binary data in PowerShell

找到的解释的比较清楚的一篇文章:PowerShell’s Object Pipeline Corrupts Piped Binary Data,其中关键部分机器翻译如下:

这就是发生的事情。PowerShell 做出一些假设:任何以原始字节形式流入的内容都被假定为文本,通过分割表示文本文件中行尾的字节,将文本转换为数组。 文本由输出文件使用标准 Windows 行尾字符重新构成。 虽然这适用于任何类型的文本,但实际上肯定会损坏任何二进制数据。使用默认的文本编码,您还会获得双倍的原始字节和一堆新的 0x0D 字节。当数据被分割成字符串数组时,损坏就会发生。在管道末尾使用二进制编码器不会正确地将数据放回,因为它总是将 CRLF 放在每个数组元素的末尾。不幸的是,由于有不止一种可能的行尾序列,所以这已经是最好的了。使用 Windows 到 Unix 转换不会修复该文件。没有办法把矮矮胖子重新组合起来。

不幸的是,由于有不止一种可能的行尾序列,所以这已经是最好的了。使用 Windows 到 Unix 转换不会修复该文件