跳转至

在macOS上用VSCode写C++代码 4 认识终端和shell

上节课我们已经打开了终端。这节课我们要深入认识终端。

先简单回顾一下:

终端提供的是一个输入命令(字符串)和输出提示(字符串)的环境,而shell则负责解析从终端输入的命令。

内建程序与内建命令

我们打开终端,这时其实相当于打开了shell。上节课我们通过shell运行了一些程序(say_hello /bin/date /bin/mkdir)。其实shell自身也带着一些程序(二进制可执行文件),这些程序就叫内建程序。

shell内建程序的独特之处是,我们在调用这些程序的时候只需要敲一个单词就行了。一个单词很短,所以我们就把它们称作内建命令。

顺带一提,系统自带的那些程序如果也能用一个单词就调用那么也可以称它们为系统命令。

内建命令有很多,我们只介绍一些比较重要的:which echo history pwd cd

与路径无关

which

查看shell如何解释后面的命令

Bash
1
2
3
4
5
which which
which echo
which history
which pwd
which cd

得到结果:which: shell built-in command

echo

将后面输入的东西返回。看起来很没用,但是在显示变量的时候会显示变量的值而不是那个字符串

Bash
1
2
echo hello
echo $SHELL

查看正在使用的shell echo $SHELL。其实还有好多其他的shell,但是我们用macOS默认的shell——zsh就好了。(小知识:在macOS 10.15 Catalina之前macOS默认的shellbash,其实二者的区别并不大,作用都是解析你输入的命令)

history

Bash
1
2
history
history -5

date

接下来我们尝试一下which date

发现shell返回了/bin/date!回顾which的作用,which会查看后面输入的东西作为命令如何被shell解析。也就是说,如果你在shell输入date,相当于输入/bin/date。那么我们要看时间怎么看啊,直接输入dateshell就会帮我解析这个单词,然后去调用在文件系统中的/bin/date这一个二进制程序,执行这个程序,然后返回当前的时间。

然后我们灵光一现,那是不是很多系统命令都可以用一个单词调用呢?

是这样的,我举一个例子。which mkdir,发现也是返回我们之前用的/bin/mkdir。那么我们以后用mkdir的时候是不是就不用写路径了,直接写单词就OK。

说明

既然不论是内建命令还是系统命令,都可以用一个单词替代,那么我们之后就不要太区分它们啦,反正都是命令,都是用一个单词告诉shell要调用哪个程序,本质上是一样的。

注:为什么会这样呢?调用程序写完整路径可以调用,但是一个单词给shellshell就能知道这个程序在哪里?好奇怪啊。原因我会在这节课的最后讲环境变量的时候提及。现在先认为这就是shell的功能好了。

与shell当前工作目录相关

刚刚我们讲内建命令的时候还说了两个命令,pwdcd。但是刚刚插着讲了shell的一些常用命令于是就跳过了。接下来我们来讲这些命令。

接下来讲的命令的一些不同是命令的输入和执行或多或少会依赖shell的当前工作目录,与文件的路径相关。

pwd

接下来开始介绍文件路径——绝对路径和相对路径

我们之前所说的路径都是绝对路径,也就是从根目录开始。但其实还有相对路径。

Bash
1
pwd

开始介绍shell的当前工作路径

. .. ... - ~

小问题:~/Desktop是相对路径还是绝对路径?(A:绝对路径。因为~/User/yangxijie是等价的)

(好的习惯是目录后面再加一个斜杠,而文件后面不加(我因为这个吃过亏,但还是懒得改))

cd

跳转shell的当前工作目录到指定的目录

这时我们就可以来验证上面学到的相对路径了

不过我们先试试绝对路径。再来相对路径

(查看命令前面的符号)

之前的程序/Users/yangxijie/Desktop/teaching_materials/say_hello,直接输入say_helloshell会告诉你它不认识这个单词,不认识这个命令

但是要调用这样的程序未免也太长了吧,我们能不能简化一些?

cd/Users/yangxijie/Desktop这时里面会有一个可执行文件

直观的想法是say_hello

但是进入目录后直接输入字符串zsh会把这个当作一条命令然后它发现并没有找到这个命令(当然了say_hello不是shell的内建命令环境变量里面也没有它所以当然出现下面的提示了zsh: command not found: say_hello

怎么让shell知道输入的say_hello不是命令而是我们想要执行的程序呢?我们输入./say_hello就好了。相当于写了一个绝对路径对吧(.相当于pwd带入)

总结

以上我们主要学习了两种内建命令:一种与文件系统/路径无关,一种与文件系统/路径有关。但是之后我们也不会去区分这两种命令了。

也就是说,之后命令就是命令,不管那是内建的还是系统的、也不管它和文件系统、路径是否沾边。

之前这么讲是希望大家能有一个较为清晰的思路认识这些命令、认识shell解析命令与执行程序的关系。但是之后在敲命令的不用太过考虑这些东西,命令就是命令,就只是一个单词、只是一句话而已。

shell常用命令

接下来我们还会再介绍一些shell常用的命令和操作。

(参考2020年清华大学电子系科协暑培|Linux

ls

列出当前文件夹下的所有文件

Bash
1
2
3
ls
ls -a
ls -l

cat

Bash
1
cat hello.txt

clear

清空终端中存在的已经执行过的命令

history仍然可以查看)

mkdir

在当前目录下创建文件夹

touch

在当前目录下创建文件(一般这么创建的文件是文本文件)

rm

移除某个文件(注意不是移动到废纸篓,而是直接抹掉,就 没了)

移除某个文件夹rm -d testDirectory

强制删除rm -rf testDirectory(使用一定慎重!!!)

mv/cp

移动文件与复制文件

移动文件到原地相当于重命名

open

Bash
1
2
3
4
open foo.md
open -a Visual\ Studio\ Code.app foo.md
open $(pwd)
open .

-a参数制定打开的程序(需要使用程序全名)

$(pwd)表示当前目录,open $(pwd)表示用Finder打开shell当前的工作目录 (open .也可)

补充:在安装好VS Code之后,可以在~/.zshrc中添加:

Bash
1
export PATH="$PATH:/Applications/Visual Studio Code.app/Contents/Resources/app/bin"

之后用在shell中敲命令code <folder>VS Code打开文件夹(工作区)。

man

date为例

(有的没有)

--help(但是有的也没有)

shell常用的操作

输出流重定向

还记得echo吗?

Bash
1
2
3
4
touch my.txt
echo "hello world" > my.txt
echo "hhhh" > my.txt
echo "hahahaha" >> my.txt

管道

|: 上一个命令(程序)的输出作为下一个命令的输入

比如我想看看我刚刚创建了什么文件夹来着:我可以一条一条翻,但是我也可以搜索啊!

Bash
1
2
history
history | grep "mkdir"

⌃C

空格

举例:创建一个含有空格的文件夹,结果发现创建了两个

加入\""

终端进阶与常用的终端操作

如果大家想对终端、shell、命令行深入了解,可以查看下面的课程:

这是对我帮助很大的一门课程

计算机教育中缺失的一课 The Missing Semester of Your CS Education 中文版

where

where也是一个shell内建命令。wherewhich的功能差不多,也是告诉我们一个命令如何被shell解析。区别是,shell能够告诉我们shell去解析这个命令的全部可能性。

Bash
1
where which

我们可以看到,其实在shell输入命令which的时候,shell觉得:啊,这个单词有两种方法可以被我解析:第一种是我自己带的内建程序;第二种是系统自带的程序;不过我自己用我自己自带的程序效率更快,毕竟是我自己的东西,所以就用自己的喽。其实,我感觉which就是where的第一行,对吧。

vim极简入门(只要能写东西进去就好了)

(编辑一个文本为例)

推出插入模式并保存退出:⎋ 冒号 wq 回车

⌃D

bash举例)

chmod

修改文件权限。

如果你希望一个文件有可执行权限:

Bash
1
chmod a+x <file>

(没有深入)

回顾

如果要总结这节课所学的终端、shell与之前课程的联系,那就是把之前很长的命令给简化了。原本调用程序的过程我都扔给shell去做,我敲命令告诉shell干什么就ok了。

比如:

简化前面的命令 之 创建文件夹

/bin/mkdir /Users/yangxijie/Desktop/newFolder这样我们可以先cd过去

前面省略程序路径是因为shell知道你那个单词代表路径为/bin/mkdir的程序,所以我们省略交给shell一个单词就好。

后面为什么可以省略呢?那是因为shell有一个叫当前工作目录的东西,因此很多绝对路径可以用相对路径来代替。我们可以先cd到需要建目录的地方然后敲mkdir newFolder

简化前面的命令 之 执行自己写的程序

之前说shell内建的程序和系统的大多数二进制程序都可以通过命令让shell帮我们执行。但是自己写的程序shell不认识

但是你仍然可以切换到相应的目录,然后用./<your_execFile>

补充:环境变量

引言

我们之前采用了几种方法来简化终端敲命令的长度:

最开始说的是:shell认识你给它的命令(单词),所以它就帮你用这个命令(单词)找到你需要执行的程序,然后执行这个程序

后来还讲过一种:因为shell自身有一个当前工作目录,所以关于路径的东西都可以写相对路径。通过cd命令cd到某个目录之后,接下来需要路径的命令都可以省略掉绝对路径而使用相对路径。

第二种的原理已经很清楚。但是,第一种,也就是最先说的那一种,shell是怎么认识我们给它的单词呢???

接下来我们简单说一下这个事情。

环境变量

查看环境变量

Bash
1
echo $PATH

其中冒号是分隔符。当你给shell扔了一个命令之后,shell先在自己的内建程序中找有没有这个单词,没找到再到环境变量去找。 (回顾where

为什么要用环境变量呢?

因为一个相同的程序,在不同的计算机上可能安装在不同的位置。

比如我写了一个python脚本,在脚本的第一行指出了我电脑里面的python路径。然后你看了这个脚本,觉得挺好用的,我就复制了一份给你。结果你的电脑上python并没有装在那里,那不就凉了吗?你执行这个我写的脚本的时候系统就找不到python的解释器于是无法运行这段脚本。

补充:添加环境变量

添加环境变量等(大家可以自己去了解一下,自己写的程序可以这么搞,但一般都不这么搞。不过你要是下个python解释器,这个时候你就要给python的解释器添加环境变量了,因为很多别的软件都会用到python,这些软件希望它们用一个单词python就能找到python的解释器。(在macOS上这件事情交给brew去做,不用你手动添加;但是Windows上可能你就要手动添加环境变量了))

其他的工具

shell脚本 - 组合你的命令

shell脚本(以我写的处理视频的脚本为例:脚本是一段代码,组合了很多命令mkv2mp4_fcp

homebrew - macOS快速安装命令行程序

homebrew(在哪里下载图形化界面的程序?App Store。那么在哪里下载命令行程序呢?当然是…Homebrew。就是一个名字。我们可以通过Homebrew来安装各种命令行工具并进行使用(补充:brew也可以用来安装一些图形化工具)brew官网)如果有机会我会出后续的教程

zsh配置文件

~/.zshrc

配置终端 - 打造舒适终端

终端配置((拿我自己的电脑说一下事儿)(给出链接大家自己想配可以配置一下)如何配置很漂亮的终端)

可以参考:

iTerm2 + Oh My Zsh 打造舒适终端体验

Mac OS 终端利器 iTerm2

如果有机会我会出后续的教程

用户与群组

用户yxjsudo rootwhoami who等(系统偏好设置的切换用户(不过看我视频教程的人应该都是用自己的mac,所以不会牵扯到这个问题。如果你是Linux服务器管理员,那么可能要设置多个用户了。))

查看所有的shell内建命令

man builtins可以查看shell的所有内建命令

man zshbuiltins可以查看到zsh的所有内建命令。(也可以先man zsh,然后在下方找到这个zshbuiltins

结束

大家估计听完这四节课都着急了,怎么还没见到VS Code的影子呢?

别急,现在你已经有了足够的基础可以听懂我接下来在讲什么,那我们就开始打开VS Code的大门吧!!!