写给前端程序员的命令行入门

2022-08-19 16:25:29 浏览数 (1)

前言

诸如React、Angular、Vue等现代前端框架严重依赖于终端。如果你还不习惯使用命令行界面,你将很难运行本地开发服务器或构建你的应用程序。

讽刺的是,我们的整个工作都建立在图形化用户界面上,但我们在开发中使用的工具却大多是基于命令行的。

除非你有计算机科学背景,或者在上世纪80年代使用计算机长大,否则你大概率不会拥有丰富的终端经验。然而,大部分在线资源都假定你已经对此十分熟练了。

要成为一个终端大佬需要多年的练习,但好消息是:我们可以走捷径。我们并不真的需要知道可以用终端做的绝大多数的事情。如果我们专注于最重要的关键基础知识,我们应该能够在很短的时间内适应命令行。✨

这也是这篇文章想要介绍的内容。它是使用现代JS框架(如React)所需的,终端基础知识的一门手册,有了它你就可以转到有趣的事情上:构建用户界面。

我还将分享我从终端中获得的技巧和窍门,这些东西我多希望在我刚开始工作时就有人能告诉我。

准备工作

好了,在开始之前,我们还需要做两件事情。

首先,我们需要一些终端软件。终端软件是运行命令行环境的应用程序。

几乎每个操作系统都会有一个内置的终端,比如MacOS的Terminal.app,或者Windows的Command Prompt ,这些应用程序都可以工作,但都不太让人满意。大多数开发者会选择使用其他软件。

只要你使用的是现代技术,那么选择使用哪款终端应用就没那么重要。因此,这里我有两个主要建议:

  1. Hyper[1]。Hyper是现代的,多平台的终端应用程序。它颜值很高,还带有一些时髦的功能,比如可以分为多个窗口。
  2. 如果你使用 VS Code 作为代码编辑器,那么 VS Code 已经内置了一个强大的、现代化的终端。这非常棒,意味着代码和终端可以在一个应用内并排运行。你可以在 VS Code 中通过选择 查看→终端 来打开终端。

在这篇文章中,我将使用Hyper来展示所有的例子。

到这里,选择好了终端应用才完成了一半。我们还需要确保运行正确的shell语言。

当我们在终端输入命令并回车时,命令会通过shell语言进行解释执行。它本质上是在终端应用程序中运行的环境。

最流行的shell语言是Bash。当你在网上看到命令行说明时,这些说明很有可能是基于Bash的。这是大多数Linux发行版使用的默认shell语言。

现代的MacOS版本自带的Zsh,而不是Bash。但Zsh与Bash十分类似:它们属于同一家族,几乎共享所有相同的命令。从目的角度出发,它们是可以互换使用的。

如果你使用的是Linux或者MacOS,那就可以正式开始了。你的计算机已经在使用一种"行业标准"的shell语言。然而,如果你使用的是Windows,我们还有一点工作要做。

形象的比喻

你是否曾经在你的浏览器中打开开发者控制台,来运行一些任意的JavaScript代码?

在这种情况下,应用程序是Chrome,而语言是JavaScript。Chrome提供了命令行界面,但当我们运行命令时,这些命令是用JavaScript解释的。

当涉及到终端时,它也是同样的道理。像Hyper这样的终端应用可能正在运行Bash shell语言。与浏览器不同的是,终端应用可以在多种shell语言之间进行切换。

Windows设置

首先,我需要承认的是,当涉及到Windows开发时,我并不是专业人士。请对我接下来说的每一句话持保留态度。

Bash是基于Linux的shell语言,它不会在Windows上原生运行。幸运的是,较新版本的Windows具有安装和运行Linux的能力,就像Linux是一种应用程序一样。这被称为Windows Subsystem for Linux,通常缩写为WSL。

这里有一个教程,介绍了所需的步骤:在Windows中,如何安装并使用Zsh[2]。

我自己运行了这些步骤,虽然这有点乏味,但它确实起作用了!

一旦设置好之后,你就可以配置终端来使用Bash或者Zsh。这里有一些关于配置Hyper来使用Zsh[3]的介绍。

如果你在这些步骤中遇到了麻烦,这里有些其他的解决方案你可以试一试。一个流行的方法是Git Bash[4],它允许你在Windows内使用模拟技术运行Bash。

归根结底,你如何做到并不重要。重要的是,你能够在Windows中使用Bash或Zsh。

Hello World

当你第一次打开终端应用时,你会遇到这个相当无助的界面:

init.png

你的终端看起来可能会有些不同,这取决于你使用的操作系统、终端应用、shell语言。总的来说,你可能会看到一行文字,和一堆空白空间。

这一行文字被称为提示。它之所以被称为"提示",是因为它在等待你提供某种指令。

我们的第一个命令,输入文本echo "hello world"并回车:

echo.png

语法有一点不同,但你可以认为命令就是内置的JavaScript函数。echo命令与JavaScript中的console.log函数非常相似。

跟函数一样,命令也可以接收参数。在本例中,echo接收了一个参数,并输出了字符串。

当我们按下回车时,命令就会立即执行,值也会被打印。下一行会呈现一个新的提示,让我们知道它已经准备好接收下一个指令。

就像这样,你已经成功运行了第一条终端命令。

跳过 $

在阅读NPM包的安装说明时,你会经常看到这样的内容:

代码语言:javascript复制
$ npm install some-package

如果你试图运行这一段文字,你会得到一个错误。这是因为美元符号($)不应该被包括在内。你应该在美元符号之后输入所有内容。

为什么安装说明会包含一个随机的符号,而这个符号实际上并不是命令的一部分?好吧,在Bash shell语言中,$ 是提示符,显示在提示的末尾。

它本质上是一个符号,并说道:嘿,这里的东西要在终端运行!

尽管在许多现代shell语言(如Zsh)中,$ 实际上并不作为提示字符使用,但其象征意义仍然存在,比如保存的图标是一个软盘形状,尽管我们已经几十年没有使用软盘了。

导航

终端的主要目的是能够让你在文件系统中移动文件,并打开/运行东西。它本质上是我们每天使用的GUI文件资源管理器(如Finder、Windows Explorer)的基于文本的版本。

为了帮助我们全方位导航,有很多终端命令可以使用。让我们来探索其中的一些。

pwd命令代表着 Print Working Directory ,它有点像购物中心地图上的“你在这里”箭头。它会告诉你当前所处的位置:

pwd.png

当你打开终端应用时,你通常会被扔进 ”home” 目录,该目录包含了 Documents 和 Desktop 目录。在我的机器上,这个目录位于/Users/joshu

使用ls(List的简写)命令,你可以查看当前目录下的内容:

ls.png

在我的终端上,目录是加粗的,并以浅水色展示。而单个文件是普通文字粗细,以白色展示。

我们可以使用cd(Change Directory)命令来移动文件系统:

cd.png

这相当于在GUI文件资源管理器中双击 "stuff" 目录。

❝需要注意的是,提示从波浪字符(~)变成了 "stuff" 。在Zsh shell语言中,默认的提示由一个箭头和当前目录的名称组成,比如说"→ Documents"。等一下,为什么之前是一个波浪字符,而不是父目录的名称?在MacOS和Linux上,波浪字符是用户home目录的缩写。在我的机器上,"~"相当于"/Users/joshu"。很容易误以为"~"是一个提示字符,就像Bash中的"$"一样。 ❞

如果我想返回上一级,返回到home目录该怎么办?我也可以使用cd命令来达到目的,但是要带有两个点(..) 。

cd...png

在大多数shell语言中,点字符(.)具有着特殊的含义:

  • 一个点(.)表示当前目录。
  • 两个点(..)表示父级目录。

如果你在JavaScript中使用过模块系统,你可能已经熟悉了这个惯例。它使用同样的符号,用两个点来表示父级目录:

代码语言:javascript复制
import { COLORS } from '../../constants';
import Button from '../Button';

关于cd命令,有件很重要的事情需要知道。那就是cd可以接收复杂的路径。终端的初学者往往会像在GUI文件资源管理器中那样,一步一步地走:

cd-step-by-step.png

这样做是没问题的,但是需要花费大量额外的工作。我们可以像这样一步到位地完成同样的路径跳转:

cd-single-bound.png

Tab自动补全

终端最令人生畏的事情之一是,它不会给你任何线索或提示。使用GUI文件资源管理器,你可以看到文件和文件夹的完整列表,以刷新你的记忆并帮助你找到你要找的东西。

如果你想按照我的建议使用cd,从一个地方一下子跳到另一个地方,看起来你可能需要一个照相式的记忆。除非你记住路径链中每个目录的确切名称,否则你无法做到这一点,对不对?

幸运的是,一个非常方便的技巧使这一切变得更加容易:tab自动补全。

在有效使用终端时,Tab键是至关重要的。除了这里展示的导航技巧外,我们还可以用Tab键来自动完成Git分支,或者补全命令的剩余部分。

试试在不同情况下按下Tab键,看看会发生什么吧。

Visual自动补全

如果你发现很难掌握Tab的自动补全,你可能会对Fig[5]感兴趣。Fig是一个终端插件,它增加了编辑器风格的自动补全。

我也刚刚开始尝试使用Warp[6],一个为速度和用户体验而建立的现代终端。在写这篇文章的时候,它是MacOS独有的,但他们确实计划在测试版之后将其移植到Windows和Linux。

我们正生活在一个终端复兴的时代,有很多工具的目的是使它不那么令人生畏。

标志

早些时候,我提到过Bash/Zsh里的命令,就像JavaScript里的函数。当涉及到标志时,这个类比就不太适用了。

标志是修饰符,以预先定义的方式调整命令的行为。

举例来说,让我们来看一看rm命令。该命令允许我们删除单个文件:

rm.png

我们没有得到任何形式的确认,但如果我们再次查看,会发现theme-song.mp3文件确实已被删除。

❝再继续之前,我应该警告你:终端可能相当不宽容。rm命令没有 "你确定吗?"的确认提示。也没有任何撤销操作。当你使用rm删除文件,它不会进入回收站/垃圾桶。它被永久地、不可逆转地删除。这是终端的一个共同主题。没有太多的安全机制。因此,在使用rm这样的命令时,请务必小心。 ❞

如果你尝试在目录上使用rm命令,你会得到一个错误:

rm-error.png

默认情况下,rm只可以删除单个文件,但我们可以使用r标志来改变规则:

rm-r.png

r标志代表着递归(recursive)。它将删除stuff目录在内的任何东西,stuff目录内的目录内的任何东西,stuff目录内的目录内的任何东西,以此类推。

你也可能遇到一些文件权限问题。由于这个原因,f标志(Force)也是很常用的。我们可以用一个破折号将多个标志分组,就像这样:

rm-rf.png

标志有很多形状和大小。按照惯例,标志通常有一个简短的形式(例如:-f)和一个完整的形式(--force)。完整形式通常使用两个破折号,并使用整个单词而不是单个字母。

让我们看个其他的例子。早前我们看到过的ls命令,通常使用两个标志调用:

  • l标志,也就是long。它将目录内容打印成一个带有元数据的详细列表。
  • a标志,也就是all。它将包含隐藏文件和目录。

这很大程度上改变了输出格式:

ls-la.png

这里有很多烦人的数据,包括令人琢磨不透的权限字符。但是一些元数据,比如显示文件最后一次更新日期,可是很有用的。

手册

为了了解更多有关命令的内容,你可以使用man命令(manual的缩写)调取它的内置文档。

man-ls.png

我要告诉你的是,man文档密密麻麻,而且经常难以解析。但它对于了解某些命令有哪些标志还是很有用的。

在某些情况下,文件会在你的默认文本编辑器中打开,但通常会在终端中打开,如图所示。这里使用了一个被称为less的程序。

要在less中滚动文件,请使用上/下方向键。在现代版本的MacOS上,你也可以使用鼠标滚轮来滚动,尽管这在其他平台上可能会导致错误的行为。

当你完成手册查看后,按q退出。它应该会恢复到典型的终端视图中。

中断命令

有些进程是长时间不间断运行,如果要停止运行,就需要进行中断。

举例来说,打开终端并尝试运行接下来的命令:ping 8.8.8.8

ping命令将检查给定IP地址的延迟情况。它对于检查一个给定的服务器是否在线很有用。8.8.8.8是谷歌DNS服务器的IP地址。

image.png

与我们到目前为止看到过的命令不同,ping是一个长期运行的进程,它永不停歇。默认情况下,它将一直ping Google的DNS服务器,直到时间结束。

当我们对结果感到满意时,我们可以通过按下ctrlc来中断该命令。即使在MacOS上,大多数的快捷键都使用的⌘修饰符,这里我们也使用ctrl

另一个很有用的命令是ctrl d。这会终止当前的会话。如果ctrl c在某些情况下不起作用,ctrl d可能会起作用。

最后,如果上面的方法都失败了,可以直接关闭当前的tab页或者窗口。该方式的快捷键取决于你使用的操作系统以及终端程序。如果是在MacOS上使用的Hyper,关闭当前窗口的快捷键组合是 w

退出Vi / Vim

有的时候,会使用Vi或者Vim来编辑文件。这些编辑器是出了名的难以退出;ctrl c在这里可帮不了你。

要在不保存的情况下退出,请遵循以下步骤:

  • 按下Escape
  • 按下: ,这应该会在终端的底部添加一个提示。
  • 输入q! ,并按下回车。

通用开发任务

到目前为止,我们已经看到了很多关于如何使用终端做事情的例子。接下来让我们来看看,如何通过终端完成一些典型的开发任务。

下面的示例假设你已经在本地安装了Node.js。如果你还没有安装,你可以从Node主页[7]下载安装包进行安装。

管理依赖

假设今天是你上班的第一天。你的团队已经允许你访问项目的源代码,你已经把源码下载到了你的电脑上。然后呢?

第一步就是下载项目的第三方依赖。

以下是需要遵循的步骤:

代码语言:javascript复制
cd path/to/project
npm install

npm代表着Node Package Manager。当你安装Node.js时,npm会自动被安装。

运行该命令会从NPM仓库下载项目所依赖的所有第三方代码。这些代码将存在于本地的node_modules目录中。

运行NPM脚本

此时,你已经下载好了第三方的代码,然后呢?

如果你查看项目的package.json ,你可能会看到这样的一部分配置:

代码语言:javascript复制
{
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  }
}

这些scripts是可以用NPM工具运行的任务。它们可以通过运行npm run [name]来执行。举个例子,为了启动一个本地开发服务器,我们会运行:

代码语言:javascript复制
cd path/to/project
npm run start

运行该命令会启动一个长期运行的进程。它启动了一个Node服务器,允许我们在应用程序上进行开发,监听文件的变动,当我们编辑文件时,重新进行打包。

当我们结束开发时,我们可以使用ctrl c来关闭该服务。

NPM脚本的美妙之处在于它们将事情标准化。startbuild,和 test 是这些标准任务的常见名称。因此,我们不必记住每个项目定制的命令,即使这些项目使用完全不同的工具。

我们也可以创建属于自己的NPM脚本。关于此,我会在后面的文章进行详细说明。

在IDE中打开项目

当我想在一个项目上开始工作时,首先我会在终端导航到项目的根目录。然后运行以下命令:

代码语言:javascript复制
cd path/to/project
code .

我们在前面提到过,.指的是当前工作目录。code是我的代码编辑器VS Code添加的一个命令。运行这个命令可以在我的代码编辑器中打开整个项目,让我可以随心所欲地在不同的文件之间轻松跳转。

需要注意的是,该命令的运行取决于你的编辑器。而且,对于在MacOS上使用VS Code的人,你需要做一些工作[8]来启用code命令。

重新安装依赖

你知道对任何电脑问题的标准建议是重启吗?

该问题的JavaScript版本是重新安装NPM依赖。有时候,只需要彻底删除并重新安装就可以解决问题。尤其是你会编辑node_modules文件并进行调试时。

我们可以这么做:

代码语言:javascript复制
cd path/to/project
rm -rf node_modules
npm install

我们进入到正确的目录后,使用rm命令删除所有的第三方代码,然后使用npm install重新安装依赖。

使用Git

虽然有GUI应用程序可以使用Git,但许多开发者更愿意使用命令行来完成与Git相关的任务。

完整的 Git 命令行教程远远超出了本文的范围,但这里有一份我常用的命令的快速小抄:

代码语言:javascript复制
// 下载Git仓库到本地
git clone [URL]
// 检查哪些文件被修改
git status -s
// 查看更改
git diff
// 添加所有文件到暂存区
git add .
// 提交暂存的文件
git commit -m "Short descriptive message"
// 创建新的本地分支
git switch -c [new branch name]
// 切换分支
git switch [branch name]
// 推送代码
git push origin [branch name]
// 开启可交互的变基
git rebase -i [branch name or commit hash]

小技巧

多年来,我掌握了一些终端小技巧。它们并不重要,但它们有助于改善开发者使用终端的体验。

循环和切换命令

许多终端程序会记录下你在一个特定会话中所运行的每一条命令。你可以使用上键循环查看先前的命令。

如果我明确知道最近运行过某条命令,通常按几次上键会比从头开始输入更快。

这里还有一个不久前学到的神奇小技巧:- 字符。

假设我们想用cd在两个目录之间来回跳动。我们可以通过输入整个路径来做到这一点。亦或者使用cd - 来快速切换到上一个cd的目录下。

清除终端

就像清空桌面那样,清空终端可以让人头脑清晰。

有好几种办法可以做到这一点。先来看看clear命令,它可以清除所有先前输入的命令,并使它看起来像你刚刚开启一个新的终端会话。

还有一个通用的快捷键,ctrl L。它与clear命令的效果相同。它应该能在MacOS、Windows和Linux中工作。

这个命令/快捷键是在Bash/Zsh中实现的。它是shell环境的一部分。这意味着它只在shell空闲时起作用。

某些终端程序也实现了它们自己的快捷键,这些快捷键甚至可以在shell繁忙时工作。下面是我所知道的快捷键的清单:

  • 在MacOS中,几乎所有的shell(Terminal.app、iTerm2、Hyper),快捷键是⌘ k。
  • 如果在非MacOS平台使用Hyper,那么快捷键是ctrl shift k

这些应用程序级的快捷键要好用得多。即使在shell繁忙的时候也可以使用它们。

比如说,假设你正在运行一个开发服务器,这是一个长期运行的进程,所以ctrl L的快捷键是不起作用的。当你开发项目时,大量的信息会被记录在终端窗口中。应用程序的快捷键允许你清除旧的日志,就像归档旧的电子邮件一样。这真的非常有用,也是现代终端程序如何使我们更加轻松的绝佳示例。

别名

每隔一段时间,我就会发现自己会重复敲一些命令。如果这个命令又长又复杂,每次都要完整的敲出来,而且要逐字逐句地记住,这就非常烦人。

Bash和Zsh都支持别名,这是一种创建自定义快捷键的方法。比如说,我可以把它设置成每当我输入hi时,它就自动运行echo "Hello World!"

alias.png

设置别名有点超出了本教程的范围,而且根据你的shell语言,说明也有点不同。这里有一些更深入的有用教程:

  • Bash 别名[9]
  • Zsh 别名[10]

切换到GUI文件资源管理器

除非你已经达到了使用终端的黑带段位,否则有时你会想在GUI文件资源管理器中打开工作目录。

在MacOS中,open .命令可以做到这一点。

open命令一般用于打开一个文件,就像在GUI文件资源管理器中双击一个文件打开它一样。

然而,当我们试图打开一个目录时,它会选择弹出一个新的Finder窗口,同时显示该目录的内容。

由于点字符(.)代表的是当前目录,所以打开.允许我们从终端切换到Finder,以继续我们在终端之外的工作。

在Windows上,你可以使用explorer .来达到同样的目的。

在Linux上,只要Linux发行版实现了FreeDesktop标准,xdg-open就可以用来打开文件,或当前目录。

链式命令

每当我从Github上克隆一个新项目时,我一般要做两件事:

  • npm install ,来拉取第三方依赖。
  • npm run start ,来启动本地开发服务器。

npm install命令通常需要花费几分钟时间。我没有足够的注意力坐在那里盯着依赖是否下载完成,所以我经常会用Twitter来分散自己的注意力。接下来我知道的是,20分钟过去了,我完全忘记了我要启动一个开发服务器。

我们可以使用链式命令来解决该问题。以下是它的工作原理:

chain.png

&&操作符允许我们将多个命令链接在一起。第一条命令将被执行,即npm install。当它完成的同时,第二个命令将自动运行。

这是一个特别巧妙的技巧,因为npm run start通常会打开一个浏览器窗口,吸引我的注意力,让我知道一切都准备好了。相比之下,npm install是静默完成的。

一旦我掌握了链式命令的窍门,我就开始到处使用它。我经常会把一堆Git命令排列在一起:

代码语言:javascript复制
git add . && git commit -m "Stuff" && git push origin main

总结

我们在这篇文章中涵盖了很多内容。希望你不会感觉到太大的压力。

终端有一个很好的名声,对初学者来说是令人生畏和棘手的。如果你对它感到费劲,那也是完全正常的。

希望这篇文章至少能缩小你需要学习的范围。可以使用终端做很多事情,但我们可以专注某一部分功能。

如果你觉得这篇文章对你有所帮助,欢迎收藏关注转发~

原文链接:https://www.joshwcomeau.com/javascript/terminal-for-js-devs/#cycling-and-toggling-commands[11]

作者:Joshua Comeau

Reference

[1]

Hyper: https://hyper.is/

[2]

在Windows中,如何安装并使用Zsh: https://candid.technology/zsh-windows-10/

[3]

配置Hyper来使用Zsh: https://hashnode.com/post/customize-hyper-terminal-in-windows-using-oh-my-zsh-and-powerline-fonts-ckggfmcwc00brrls1f8va9jfl#install-hyper-terminal

[4]

Git Bash: https://www.atlassian.com/git/tutorials/git-bash

[5]

Fig: https://fig.io/

[6]

Warp: https://www.warp.dev/

[7]

Node主页: https://nodejs.org/en/

[8]

一些工作: https://code.visualstudio.com/docs/setup/mac

[9]

Bash 别名: https://linuxize.com/post/how-to-create-bash-aliases/

[10]

Zsh 别名: https://linuxhint.com/configure-use-aliases-zsh/

[11]

https://www.joshwcomeau.com/javascript/terminal-for-js-devs/#cycling-and-toggling-commands: https://www.joshwcomeau.com/javascript/terminal-for-js-devs/#cycling-and-toggling-commands

0 人点赞