换了一家公司,新公司的网络环境只支持Windows,于是从Mac切换到了Windows。由此遇到了很多很多的问题,在此记录一些比较典型的问题。
使用Windows时,偶尔会遇到需要使用命令行的场景,常常会遇到以下问题:
- 如果一行命令太长需要换行,常常弄不清楚究竟应该怎么换行。有时应该使用'|',有时应该使用'`',有时又需要使用'^'。关键是,这一次使用了一种换行符,下次写其他命令时再使用就会报错
- 从网上拷贝下来的命令一运行就报错
- 承接上一点,更过分的是,以往自己记录下来的命令再运行有时也会报错
以上的问题,很有可能是下面这个问题导致的:
Windows Terminal可能随机加载Power Shell或者CMD。
缘起
在Windows出现之前,微软旗下的操作系统是1981年发布的MS-DOS,这时的操作系统都是纯命令行的。
后来,随着Windows 3.1 和 Windows 95的推进,图形界面成了主流。但是这时就出现了一个问题,以前DOS时代的那些软件怎么办?于是微软开发了一个软件,Command Prompt命令提示符,它的简写就是CMD,旨在图形界面中提供一个DOS的仿真环境,以供以前DOS时代的软件使用。
随着时代的发展,CMD越来越不讨喜了。比如CMD只能处理文本,这意味着用户需要手动解析命令输出的文本内容,这既麻烦又容易出错。在这个背景下,微软于2002年开始了一个名为 “Monad” 的项目。这个项目的初衷是为系统管理员提供一个更强大的自动化工具,以应对日益复杂的 Windows 服务器环境。而Monad 项目的核心理念是:命令行应该处理对象,而不是纯文本。
经过几年的开发,Monad 项目在 2006 年正式发布,并更名为 PowerShell 1.0。它作为 Windows XP、Windows Server 2003 和 Windows Vista 的一个可选组件推出。
随着时间的流逝,Windows上的命令行又面临了新的问题。长期以来,Windows 上的命令行工具,比如命令提示符(CMD)和 PowerShell,都运行在一个古老、功能有限的控制台窗口里。这个窗口不支持标签页、主题、分屏等现代终端应有的功能,这让开发者和系统管理员的工作效率大打折扣。
在2019 年 5 月,在微软的 Build 开发者大会上,微软宣布了 Windows 终端(Windows Terminal)项目,该项目在2020年发布了1.0版本,并于Windows11中变成了系统默认命令行宿主应用程序。
关系解读
我们开篇提到的那些问题就出在这个Windows11的系统默认命令行宿主应用程序上。
首先我们要理解CMD、PowerShell、Windows Terminal的关系。
CMD 和 PowerShell 是命令行解释器或者说是命令处理器,它们是执行命令的核心逻辑层,负责实际处理指令。
Windows Terminal 是一个命令行宿主应用程序,它为这些解释器提供了一个用户界面,即一个UI层。
它们的关系可以用下图表示:
![[Windows下命令行使用-三者关系.png]]
在Windows11中,命令解释器除开PowerShell
和CMD
之外,往往还有Azure Cloud Shell
和WSL
对应各种Linux
环境。而这些环境默认的UI都是Windows Terminal
。
理解了这些环境的关系,我们再回到最初的问题。
Windows Terminal可能随机加载Power Shell或者CMD。
问题
在Windows11之前,不同的命令解释器会有自己不同的UI界面,用户通过使用不同的入口程序打开不同的命令解释器,而且可以通过界面的不同轻易的判断当前使用的是哪个环境,不会搞混。
但是在Windows11中,Windows Terminal
成为了系统默认命令行宿主应用程序,即所有的命令解释器默认都会通过它打开。
虽然设置了Windows Terminal
的默认环境是Power Shell
,但是它仍然有概率使用CMD
,而两者之间的区分并不明显。这就是为什么会有开篇提到的那些问题:Windows Terminal
的底层环境不同了,当然能够使用的命令、对应的换行符都不相同。
打开Window Terminal
,加载了Power Shell
环境:
打开Window Terminal
,加载了CMD
环境:
在使用终端时一定要注意两者的区别!
CMD
和PowerShell
的使用细节
对于CMD
,它的换行符是^
。
对于PowerShell
,它的换行符是`(反引号)。
其实这两个符号就是它们分别的转义符
,它们之所以能实现换行的效果,是因为命令解释器在执行命令时,会取行首到换行符(比如\n)为一行命令。而在换行符前面添加了转义字符,那么命令解释器会将这个换行符识别为命令中的一个文字,从而继续解析文本,直到下一个换行符。但是对于UI层,仍然会识别出这个转义后的换行符,从而实现UI层面的命令换行。