作为 2024 年五一「生产力超频」系列目优惠活动的一部分,本期设置为限时免费,欢迎观看。我们将在 5 月 1 日至 7 日,为热门付费栏目「生产力超频」全系列设置七折优惠;同时,我们将每天从不同教程中选出一篇,设为限时免费。希望这些内容和优惠为你助力,开启一个效率和技能「超频」的五月。进一步了解

今天的限时免费内容来自《Windows 命令行实用手册》,带你掌握 PowerShell 命令的基本语法及风格。本栏目从完全新手的角度出发,通过使用一个个命令行工具,带读者逐步掌握其背后的概念。如果你已经了解了基本概念和用法,栏目中也准备了能进一步挖掘 Windows 命令行潜力的进阶内容。栏目原价 59 元,折后价 41.30 元(节省 17.70 元)。前往购买


读到这篇文章的时候,你已经理解了 shell 和终端的概念,并且认识到 shell 命令和外部命令的显著区别,此外,你还了解到命令行可以配合快捷方式、任务计划程序、AHK 等各类应用,使它们更加灵活方便。

同时,在前面两篇文章中,我带着大家操作了 ytp-dl、adb 等十几个命令行应用,大家照着文章给出的代码,也实际地完成了不少任务,但相信你一定不满足于文章列出的例子,想要自己学到更多的命令。

所谓「授之以鱼不如授之以渔」,这篇文章会教给大家自行探索命令行世界的方法,快速掌握任何新的命令行应用,同时帮助初学者准确地定位输入命令时的错误。本文主要解答四个问题:

  • 学习使用命令行,最重要的是学会什么?
  • 如何查看命令行应用的文档?
  • 有哪些类型的命令行应用?
  • 如何像设置 GUI 应用一样设置命令行工具?

理解命令行的语法

仔细琢磨的话,「学习使用命令行」这个话题似乎有些奇怪。因为命令行应用也是应用程序,类比来看,经常使用手机的用户很少会问「如何使用淘宝」、「如何使用微信」等问题。

可命令行偏偏不同,如果我不在第一篇文章中告诉大家 Word 可以加 /t 参数,你可能从来没想过 Word 可以这么用。因此有一种观点认为,CLI 最大的缺陷就是「可发现性」差。

但事实并非完全如此。之所以许多人会觉得命令行难,是因为他们习惯了另外一种逻辑。还记得第一篇文章中我如何阐述 CLI 作用的吗?

应用有许多种使用的方法,鼠标辅以键盘、快捷键、命令行都是和应用交互的一种途径。

以手机 App 为例,所有手机应用都在一套统一的交互逻辑的框架下:

  • 点击操作意味着确认、进入;
  • 按住操作意味着菜单、更多;
  • 滑动操作意味着滚动内容,移动焦点。

只要理解了点、按、滑这三个基本操作,不用任何人教我们也能掌握一个新 APP 的基本用法。桌面端的应用交互也有类似的逻辑,鼠标左键、右键、中键不正是对应着确认、更多和滑动吗?反过来说,你会觉得各种快捷键记起来很麻烦,背后的原因是不是快捷键背后缺少一套统一的设计逻辑呢?

这就是第一篇所说的「和应用交互的途径」的本质。掌握了点按滑就会使用手机的各种应用,那学会了什么样的逻辑,就学会了所有的命令行应用呢?

和 GUI 不同,命令行中,我们就像写文章一样是通过输入字符来完成任务的,因而使用命令行的逻辑表现为语法(Syntax)。就像所有手机 App 都能点、按、滑一样,无论是 PowerShell、cmd 还是 Bash,所有运行在 CLI 上的命令都遵守着一些共同的语法规范。

我们不妨把之前用过的几个命令写在一起:

yt-dlp https://www.bilibili.com/video/BV1jS4y1o7Fc --output D:\Videos\sspai_test.mp4 --write-thumbnail

choco search youtube-dl -r -e

VirtualDesktop11 /w /right

powershell -nologo -file D:\tools\init.ps1

尽管它们功能、用法大相径庭,但命令的构成却出奇地一致:命令名,动作,参数,它们之间以空格分隔。命令行的语法可以总结为:

命令名 动作 参数1 参数2 参数3 ……

shell 环境下各种命令都能抽象为上面的结构,只不过它们在某些字符的写法和顺序上有所不同,一些命令可能没有后两个部分。我们暂且把命令间的区别放一边,先逐个部分解释其中的共性。

命令名

第一部分是命令名。无论使用什么命令,都必须先叫出它的名字。就像分配任务时,必须先指定负责人一样。对于外部命令而言,命令名就是外部应用的文件名。在前面的学习中,我们既看到过简短如 notepadchoco 的应用名称,也认识到:如果应用所在路径没有加进环境变量,就必须写出应用的完整路径,否则 shell 就会报错:

该输入什么命令名,取决于应用开发者给他的应用起了什么名字,我们能用 where.exe 看到外部命令的具体路径。不过那些自行下载到本地的应用,我们完全可以把它们改成自己喜欢的名字,下图中我就把之前用到过的 yt-dlp.exe 重命名为 yt.exe,执行起来也没有任何问题:

和类 Unix 系统不同,Windows 文件系统不区分大小写,因而应用名也不区分大小写。pingPING乃至 piNG 都是同一个应用:

如果一个应用的完整路径含有空格,必须加双引号。因为一行命令的不同部分之间就是用空格分隔的,如果不加引号,shell 就会把它当作几份分别解析。此外务必记住,和 cmd 不同,PowerShell 在执行加引号的命令时,前面必须加 &(见下图第三条命令),背后的原因我们之后会学到:

动作

第二部分是动作。如果说命令名对应着一句话的主语的话,那么动作部分就相当于谓语和宾语。不同的命令的动作部分可能是类似的,例如 scoop install yt-dlpchoco install yt-dlp 都是安装 yt-dlp 的意思。要想理解一行命令的功能,第一和第二部分是关键,例如 Chocolatey 还原代理的命令:

choco config unset proxy

命令名是 choco,后面都是动作部分,读起来像是一句精炼过的句子:

choco 配置 取消设置 代理

一些应用本身功能单一,命令名本身的意指就非常明确了,那么它就不需要第二部分。譬如第二篇文章中提到的 Chrome,用命令行的方式调用它的时候,Chrome 唯一的作用就是打开浏览器。

参数

真正的难点在于第三部分参数,它的作用是详细规定一个动作要如何完成。很多情况下,学习命令行工具就是在学参数。一个命令可以有几十个参数,它们看似复杂,实际也有规律可循。

参数部分由特殊符号开头。本节一开始列出的四个命令,它们的参数前面是 -(减号)、--(两个减号)或 /(斜杠)这三种特殊符号,后面则是相对贴近自然语言的字母或者单词:virtualdesktop /w /right 的作用切换到右侧的桌面,参数 right 指向右,参数 wWrap 的缩写,表示当切换到最右侧的桌面时,绕回第一个桌面。

在下面这行命令中:

powershell.exe -nologo -file D:\tools\init.ps1 

我们还能发现两类不同参数:-file D:\tools\init.ps1 是常规参数,其结构是 参数名 参数值,也就是说D:\tools\init.ps1file 的具体值。对于常规参数而言,一旦我们写了参数名,往往需要为它指定一个合适的数值:

参数名和参数值的连接方式因应用而异。大多数命令用的是空格,不过也有用 = 或者 : 的案例。譬如用 choco 锁定应用(不进行更新)的命令:

 

choco pin add -name=<应用名>

这里用的就是 = 号。

常规参数之外,-nologo 被称为开关参数(switch parameter)。这类参数只有是和否两种状态。如果我们不写 -nologo,那么 PowerShell 就会显示版权信息,反之则会隐去相关信息。choco 命令中的 re 也是类似的道理。

参数的大小写和命令名不同,是由应用开发者控制的。-f-F 极有可能是两个不同的参数,因而在输入参数的时候务必小心。

了解完命令的三大主要成分,在键入命令时你应该会更有信心了。但理解了命令行的语法并不足以帮助我们掌握陌生的命令,我们还需要明确地知道一个命令可以加哪些动作,有哪些参数。

阅读命令行工具的文档

如果诸位有过自行清洗大型家电以及保养汽车的需求,那么家电的说明书和汽车的保养手册一定是参考资料之一。想要知道一个命令的动作、参数,最优解也是阅读命令行工具自带的说明书,计算机领域我们更愿意称之为文档。

命令行工具的自带文档

那么调出命令行工具的文档呢?联系上一节的内容,「帮助」一词作为关键字可能出现在动作或者参数部分中:

command help # 命令名 + 动作(help)
command /? # 以 / 开头的参数
command /h # 以 / 开头的参数
command -h # 以 - 开头的参数
command --help # 以 -- 开头的参数

以上五个命令逐个试下来,能调出绝大多数命令的文档。比如说,chocoscoop 的文档用的是命令名 + help 的形式查阅;cmd 的帮助文档可以用 cmd /? 调出;第二篇文章末尾提到的 VScode 命令的帮助文档是用 code -h

一些命令,比如说 yt-dlp,运行失败后会直接告诉你如何调出帮助文档:

yt-dlp --help

这些文档就像一本字典一样,详细地告诉你命令的每一个用法以及每一个参数的含义。从头看到尾并不推荐。很多人都会用 Photoshop,但为了简单修图而去学习 Photoshop 的所有选项并不明智。我们需要有目的地看文档,着重把握三个要点:

  • 具体语法
  • 需要的参数
  • 示例

请大家使用包管理器下载 Node.js,它包含了一个简单的命令行工具 npm,可以安装第三方的 JavaScript 包。下面我们以这个场景为例,利用自带的文档找到全局安装 fanyi 包的命令,这是一个用于终端下的中英翻译工具。

首先自然是查阅 npm 的文档,逐一尝试本节开头列出的五个命令,发现 npm help 就能调出文档:

我们需要的是安装(install)一个工具,恰巧对应了文档中对 npm install 的解释。不过这行说明过于简短,再往下看,能发现 npm <command> -h 命令,功能是展示某个命令的帮助文档。所以我们需要再执行 npm install -h。顺便一提,要是你觉得用鼠标滚动太麻烦,在 PowerShell 中可以尝试 Ctrl + L 快捷键,它会将当前输入行置顶:

这次展示的文档就更加详细了,它明确告诉我们用 npm 安装一个工具的具体语法是:

npm install [<package-spec> ...]

这行表述用到了两对特殊的符号,[]<>,在命令行工具的文档中,它们有固定的意义,[] 代表可选成分,<> 代表必选成分。也就是说,npm install 后面不加任何东西也能执行成功,但如果要添加什么,必须填上 package-spec,也就是包名。

因为目的是全局安装,就直接在文档中寻找意义近似于全局的参数。Windows 终端也有查找功能,我们可以用 Ctrl + Shift + F 调出:

果不其然让我们找到了 [-g | --global] 参数。方框后中两个参数分布在|(竖杠)左右,这或意味着前后两个参数互斥,或意味着两者功能相同,因而,全局安装 fanyi 的命令应该是:

npm install fanyi -g

## 如果下载慢,请改用下面这行命令调用国内镜像。
npm install fanyi -g --registry https://registry.npm.taobao.org

在参数部分的后面,npm 还提示我们能运行 npm help install 能获得更多的信息,这会用浏览器打开官网的文档,里面有每个参数更详细的解释。

上一步中,我们成功地安装了 fanyi,npm 会帮我们处理好环境变量的问题。大家不妨自己尝试着调出 fanyi 的文档,看看如何用它在不发音的情况下翻译一个单词。

经过一番尝试,你最终会发现能用 fanyi -h 或者 fanyi --help 调出其文档:

说实话,它的文档写得并不好,具体语法部分和其他部分有冲突,此时示例就非常有用了。列出的三个例子都是用 fanyi 命令名直接加需要处理的词句,文档中又列出了 -S (大写的 S)参数,其功能不发音。之前提到过有的命令参数区分大小写在这个命令也有体现,小写的 -s 参数意味着发音。用它来翻译「kepa」这个单词的命令是:

fanyi kepa -S

在网络中搜索文档

当然,除了阅读应用自带的文档,网络永远是我们的好帮手。对于一些命令而言,网络也是获取它们详细用法的唯一渠道。

想要得到命令的具体用法,最好的去处一定是应用的发布处,例如开发者的网站或者 GitHub。比如说我想知道 Word 支持哪些参数。因为 Word 并非为在命令行中使用而设计,所以我们是不能用 winword help 之类的命令调出其文档的,此时,就要在搜索引擎中检索关键词:「microsoft word cli parameter」,输入关键词会比「how to use word in terminal」之类的句子更高效:

上图的三个结果中,排名第一的是 Word 的开发商微软的网站,所以那里大概率就有最权威的答案:

网友发布的帖子同样有参考价值。命令自带的文档也好,官网给的详细说明也好,都是教科书一般的存在,尽管事无巨细,但少了些针对性。例如,第二篇中提到的图片处理工具 magick,它的文档和官网给的说明多达数十页。假如我只想用它来将图片转换为 jpg,并且保留原来的文件名,倒不如「抄网友的作业」,检索「magick convert to jpeg same name」:

排名第一的是知名的 IT 技术类问答社区 stack overflow,简单浏览就能得到想要的答案:

不过「抄作业」也要建立在对命令基本的了解之上。网页中给的命令是 mogrify -format png *.psd,其作用是将 psd 转换为 png,如果你尝试直接运行,shell 会报错,你必须事先知道 magick 的基本语法是 magick tools ……,所以我们需要的的命令应该是:

magick mogrify -format jpeg <path>

 

这同时是本文写作的目的,理解了命令行的基本规范,简单翻阅了命令的文档,复制粘贴才会有意义。

前面介绍了两种查阅命令行说明书的方法:调用自带的文档和网络搜索,一开始阅读这些文档可能有些吃力,但随着积累越来越多,我们能够从中找到一些共性,举一反三。这时候,仅需稍加提示,我们就能直接猜出命令,而最好的提示就是命令的具体使用示例。因此,真的有人做了这样一个网站,收录了大量的命令行工具的具体示例,域名也非常好记:shell 的小抄:https://cheat.sh/

网站首页写着使用方法:执行 curl cheat.sh/<command> 或者缩写版 curl cht.sh/<command>。cURL(choco install curl -y)是用于发送和处理网络请求的命令行工具,安装此工具后,假如我想知道浏览器 chromium 命令的具体用法,只需执行 curl.exe cht.sh/chromium(PowerShell 5 请不要省略 curl 后的 .exe):

数行文档,基本涵盖了各种常见的使用情况,虽然不能替代官方的说明书,但它提供的「太长不读」版本着实能省下不少时间。

三类不同的命令风格

而在我们接触了这么多命令行工具之后,不难发现,在 命令名 动作 参数 这个组合中,外部命令的前两部分都大同小异,但参数部分则各有特点。根据这些特点,我们可以将外部命令分为三类。了解完这三种「模具」,你便能更快地掌握新的外部命令。

Unix sh 风格

计算机发展过程中,在 Unix 时代几个最为流行的 shell —— sh(bin/sh)、Bash(/bin/bash)影响下,命令行的最初规范逐步确立,之所以 Linux、macOS 等 Unix-like 系统上的各类 shell 命令基本一致,便是因为它们或多或少都遵循着这些习惯。

现代的开发者们在设计自己的应用时,常常倾向于和类 Unix 系统上的 shell 命令风格保持一致。因而,Unix sh 风格的外部命令非常常见。比如说我们刚刚用到的 cURL,通过文档观察其语法和参数:

命令的特点是:

  • 参数大多由 - 或者 -- 开头;
  • - 后接短参数,即一个字母,-- 后接长参数,即完整的单词,多个单词由 - 连接。前者往往是后者的简写形式;
  • 参数名和参数值之间往往由空格或者 = 连接;
  • 参数区分大小写;

以上四点是所有 Unix sh 风格命令的共有特征,如果碰到了这类命令,使用 command --help 大概率能调出其文档。

不只是 cURL,我们用过的 npm、yt-dlp 等大部分应用属于此类风格,比如说当初我们用 yt-dlp 下载视频的命令是:

yt-dlp <url> --output D:\Videos\sspai_test.mp4 --write-thumbnail

命令的文档告诉我们参数 --output 有一个简写形式 -o,因此,它和下面的命令是等价的:

yt-dlp <url> -o D:\Videos\sspai_test.mp4 --write-thumbnail

又因为 Unix-like 风格的命令区分大小写,所以千万不要写成了 yt-dlp <url> -O ……

不过有时候你会看到这类命令的短横线后跟了不只一个字母,比如说 curl -fsSLgit -am,这并没有和 Unix sh 风格冲突, 而是同时指定多个短参数的简单写法:curl -fsSL 等同于 curl -f -s -S -L

Windows cmd 风格

从各种意义上,Windows 都不遵循许多类 Unix 系统奉为圭臬的种种习惯。cmd 是微软从 MS-DOS 基础上拓展而来的 shell,这也造就了 Unix sh 风格之外的 Windows cmd 风格,它的典型例子就是 cmd 本身了:

其特征是:

  • 参数开头是 / 符号,其后既可以是字母,也可以是单词;
  • 参数名不区分大小写;
  • 参数名和参数值之间由空格或者 : 连接。

调出它们的文档的方法是 command /?。除了 cmd,之前我们用过的 Word、VirtualDesktop 都属于此类。实际上,大部分 Windows 预置的外部命令,以及专门为 Windows 写的应用一般都遵循这类风格,例如 Windows 自带的电源管理小工具,powercfg.exe:用它来生成一份电池使用报告的命令是:powercfg.exe /BATTERYREPORT,将参数小写也是没问题的:

相较于一板一眼的 Unix sh 风格,这类的命令设计得非常宽松,一些命令支持省略参数前的 / 符号,或者用 - 代替,这也是为什么大家能在网络上看到同一个命令的各种写法。我仍然建议大家统一地使用 /,因为并非所有应用都支持此特性。

PowerShell 风格

第三种风格的命令更好理解,其特点是:

  • 参数由 - 开头,- 后可以是单词或字母;
  • 参数不区分大小写;
  • 参数名和参数值之间一般用空格分隔。

查阅这类命令文档的方法一般是 command -help,可以缩写为 -h,少数跨平台的应用倾向于使用这种风格,前文展示过的 PowerShell、magick 都属于此类:

这是最简单的一类命令,我们只要记住它的参数是由 - 引导的即可。但它们的缺点是命令写起来往往很长。

命令行工具的设置和配置文件

随着学习的深入,我们接触到的命令行工具越来越多,大家可能会有这样的感触:「一些命令打起来很麻烦,如果能简化一下就好了」。确实如此,就以前面用过的两行命令为例:

yt-dlp <url> --output D:\Videos\sspai_test.mp4 --write-thumbnail
npm install <package> -g --registry https://registry.npm.taobao.org

第一行命令中的 --output 参数功能是将下载的视频存到固定的文件夹,如果我要下载十几个视频,每一次都打一遍存储路径是不是过于繁琐了;类似的,难道每一次安装 npm 包都要写一遍 --registry 参数吗?

大家可以回想一下在 GUI 中我们是怎么做的:使用手机 App 时,浏览一遍设置面板中有哪些选项,按自己的习惯调整后,这样做才能用得舒服一些。换句话说,GUI 的某些设置是可以固化下来的。其实命令行工具也有同样的设计。

一些命令行工具提供了单独的 config 动作,我们执行一遍后,设置就能永久生效。例如,为 npm 全局配置国内源的命令为:

npm config set registry https://registry.npm.taobao.org

将 choco 的下载路径调整为 D:\Downlaods 的命令为:

choco config set cacheLocation $home/Downloads

在使用这些命令前大家可以仔细阅读文档,看一看有没有相应的设置:

更多情况下,命令的设置藏得比较隐蔽,我们能在其官网找到相关的说明,以 yt-dlp 为例,官网提到,可以在 %APPDATA%/yt-dlp 目录下新建一个 config 文件,将常用的配置写入其中:

假如我们想让 yt-dlp 下载的视频始终存放在 D:\Videos 文件夹下,并且设置代理 127.0.0.1:3128,就新建一个配置文件,然后写入:

# Use this proxy
--proxy 127.0.0.1:3128

# Save all videos under YouTube directory in your home directory
-o D:/Videos/%(title)s.%(ext)s

如此操作后,我们以后就能直接用 ytp-dl <url> 的方式下载视频了。

事实上,config 动作的实际做的也是修改了存放在某处的文件。npm 的文件是用户目录下的 .npmrc,choco 的则是 ProgramData\chocolatey\config\chocolatey.config

我们习惯于称这类文件为配置文件,因为它们往往以点号开头,英文资料中多用 dotfile 来指代。这和 GUI 应用的设置界面是同样的道理,只不过一个是有图形化界面,另一个只是纯文本而已。GUI 的设置入口多种多样,命令行工具的配置文件的路径也多种多样,Windows 环境下,开发者一般会选择将其设计在如下三个目录下:

  • 用户目录:即 C:\User\<UserName>\,可能默认被隐藏;
  • AppData 目录:~\AppData\Roaming\ 或者 ~\AppData\Local 下的应用开发者亦或应用名文件夹;
  • C:\ProgramData 目录:此文件夹为隐藏状态。

总结

本文是有关外部命令的最后一篇文章,解答了前两篇文章留下的诸多问题:

  • 命令行有统一交互逻辑:语法,也就是 命令名 动作 参数1 参数2 ...
  • 想要了解一个命令的详细用法,可以使用自带的 help 命令调出帮助文档,也可以查阅网络资料。熟练之后,curl cht.sh/<command> 可以帮你省下不少时间;
  • 有三类不同风格的命令,以 --- 引导参数的 Unix sh 风格,参数以 / 开头的 cmd 风格,以及最为简单的 PowerShell 风格;
  • 像 GUI 一样,我们能用配置文件的方式固化命令行工具的设置。

学习完这一篇文章,绝大多数外部命令都难不倒你了,同时如果你回过头去看第一篇和第二篇文章中的那些例子,也应该会有更深的理解。

下一篇文章会从操作文件这个场景切入,讲述 shell 命令。它的使用场景自然也不只是和系统交互,和外部命令不同,shell 命令有着「胶水」一般的效果,我们将不再局限于一行一行死板地执行命令,完成更加复杂的任务。