计算机教育中缺失的一课——Shell

2021/04/22

同学们,大家好,今天我是来补课的。

上一篇」把命令行、终端、Shell 搞清楚后(还没搞清楚的可以点击蓝字过去看一眼),今天这篇写起来就顺畅多了。哦,极度的舒适!

开门见山地说吧。大学里的计算机课程通常专注于讲授计算机操作系统、计算机组成原理、计算机网络等学院派的课程,以及某一门具体的编程语言,比如说 Java、C++/C,而对于如何精通工具这个主题往往不在讲授的课程之内,需要同学们自行摸索。

但实际上呢,某些工具的使用频率高到可以使用一个成语来形容——朝夕相伴。比如说命令行,不仅在学生时代经常用到,工作后更是形影不离。因此,花一些时间来打磨使用这些工具的能力就变得迫在眉睫。比如说今天的主角——命令行 Shell,项目的运维基本上都是通过 Shell 完成的。

记得刚参加工作那会,需要向一名前辈请教线上部署的问题。我站在他的身后,看着他灵巧地手指在键盘上熟练地操作着,黑色的 XShell 窗口里,彩色的字符在愉快地跳跃着,有一种杰伦在钢琴上弹奏《逆鳞狂想曲》的感觉,特别崇拜。

01、再说 Shell 是什么

现代计算机的交互接口多种多样,从常见的图形化界面,到语音输入,再到 AR 和 VR,都可以满足指令的输入。这些接口可以覆盖绝大多数的应用场景,但它们从根本上限制了另外一种操作方式——你不能点击一个不存在的按钮,或者使用语音输入一个还没录入的指令。

为了能充分地利用计算机的能力,我们有时候不得不回到最原始的交互方式——文字接口:Shell,一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。

几乎所有的操作系统都支持某种形式的命令行 Shell,有些甚至提供了多种 Shell 可供选择。Linux 上常见的 Shell 有:

  • Bourne Shell(/usr/bin/sh 或 /bin/sh)
  • Bourne Again Shell(/bin/bash)
  • C Shell(/usr/bin/csh)
  • K Shell(/usr/bin/ksh)
  • Shell for Root(/sbin/sh)

虽然细节上有些许差异,但核心功能是一样的:允许你执行程序,输入指令并获取某种半结构化的输出。

可通过 cat /etc/shells 命令来显示本机上的 Shell。我用的 Mac,上面有 bash、csh、ksh、sh、tcsh、zsh 等等。

默认是 zsh,在窗口标题上可以看得出来。如果想切换到另外一种 Shell,可以直接敲 Shell 的名字,比如 tcsh,见下图。

害,一不小心还是暴露了自己的名字。如果想退出当前 Shell 到默认 Shell 的话,敲 exit 命令就可以了。

02、初用 Shell

在启动台找到“终端”,打开(我用的 Mac),如下图所示。

先从窗口标题说起,重点是 zsh。

2019 年,Apple 发布了新一代 macOS——macOS Catalina,为专业用户带来了一项重大变化,zsh 取代了 bash,成为默认的 Shell。相比 bash,zsh 拥有更强大的功能,比如说更智能的自动补全、更丰富的主题等等。这逼绝对是马车中的跑车,跑车中的飞行车,史称「终极 Shell」。

再说说窗体内容。

第一行内容显示了最近一次的登录时间。有些同学会好奇,“ttys000”是什么鬼?

简单来说,tty 是终端的统称。看过「终于制服了它们」的同学应该知道了,早期的终端是电传字打印机(Teletype / Teletypewriter),英文缩写就是 tty。虽然终端设备已经不再限制于电传打字机了,但是 tty 这个名称还是就这么保留了下来。

“ttys000” 就是 tty 加了一个代号 s000。

第二行内容告诉我们,主机名是 itwanger。可通过「系统偏好设置」→「共享」→「电脑名称」→「编辑」修改主机名。% 后面跟了一个提示符,可以在此输入任意字符,只不过有些可以被 Shell 解析,有些则不能。

03、Oh My Zsh

zsh 本身非常强大,但配置复杂,对普通用来来说体验非常差。直到有一天,有个无聊的家伙开发出了一个能够快速配置 zsh 的项目,叫做「Oh My Zsh」,GitHub 地址如下所示:

https://github.com/ohmyzsh/ohmyzsh

这玩意安装起来极为简单,能够让我们神功速成,有点「五分钟学会 XXX」的味道。

直接在终端里执行 sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" 就可以自动安装 Oh My Zsh 了。

如果自动安装失败的话,可以尝试手动安装。

git clone git://github.com/robbyrussell/oh-my-zsh.git ~/.oh-my-zsh
cp ~/.oh-my-zsh/templates/zshrc.zsh-template ~/.zshrc

由于某些原因,速度可能会比较慢,耐心地等待一会。

安装完成后重新打开一个新的终端,就可以看到彩色的提示符(Oh My Zsh 默认主题的标志)了。

Oh My Zsh 的配置集中在 ~/.zshrc 文件里(~/ 表示根目录),可以通过 vim 打开。

vim ~/.zshrc

可以看到,Oh My Zsh 默认使用的主题是 robbyrussell,可在 ~/.oh-my-zsh/themes 目录下找到更多主题进行切换。

如果你不知道选择哪个主题,可以通过下面的网址进行预览。

https://github.com/ohmyzsh/ohmyzsh/wiki/External-themes

如果你有选择困难症,可以像我一样,配置成随机,每新开一次窗口,Oh My Zsh 就替你选一次。

ZSH_THEME="random"

现在,就新开一个窗口吧,可以看到主题随机到了 essembeh。

再来说说插件。Oh My Zsh 提供了完善的插件体系,默认有 100 多种,可以在 ~/.oh-my-zsh/plugins 目录下找到这些插件。如果不确定这些插件是干嘛的,可以查看一下插件目录下对应的 README.md 文件。插件的配置同样在 .zshrc 文件里,目前默认的插件只有 git。

到此为止,Oh My Zsh 的安装、配置、插件完成了三位一体,终极 Shell 全面登场。

04、再用 Shell

来执行一个最简单的命令 date,不出意外的话,它将会打印出当前的日期和时间。

然后,光标等待我们输入其他命令,我们可以在执行命令的时候带上参数。

echo hello

echo 命令会将参数 hello 打印出来,Shell 是基于空格分隔命令进行解析的,第一个单词代表可执行的程序,后续的单词作为传递给程序的参数。如果你希望参数里包含空格的话,可以使用单引号或者双引号包裹起来。

echo "hello world"

当我们在 Shell 中执行命令时,实际上是在执行一段 Shell 可以解释执行的简单代码。如果命令不是 Shell 的预知范围之内的话,它会去咨询环境变量 $PATH

可以使用 which 命令来确定某个程序名代表的是哪个具体的程序。也可以绕过 $PATH,直接使用带路径的命令来执行,比如 /bin/date

Shell 中的路径是一组被分割的目录,在 Linux 和 macOS 上使用的 / 分割,在 Windows 上是 \,正因为这样,我们在编程的时候一定要先获取系统的分隔符(Java 是 File.separator 获取的),不然会导致程序在不同的操作系统下无法执行!

如果某个路径以 / 开头,那么它就是一个绝对路径,其他都是相对路径。当前工作目录可以通过 pwd 命令来获取,切换目录通过 cd 命令。. 表示的是当前目录,.. 表示上级目录。

Shell 会实时显示当前的路径信息。可以通过 ls 命令查看当前目录下包含哪些文件,安装了 Oh My Zsh 后,还可以通过 ll(其实是 ls -l 的简写)显示文件或者文件夹的详细信息。

简单来介绍一下文件属性,以后会很有用。

  • d:第 1 位表示文件类型,d 是目录、l 是链接文件、- 是普通文件。
  • rwx:第 2-4 位表示这个文件的所有者拥有的权限,r 是读、w 是写、x 是执行。
  • r-x:第 5-7 位表示和这个文件的所有者所在同一个组的用户具有的权限。
  • r-x:第 8-10 位表示其他用户所具有的权限。

比如:

-rw-r--r--   1 maweiqing  staff     6B  1 12 16:35 hello.txt

表示 hello.txt 是个普通文件,maweiqing 拥有读和写的权限,但没有执行的权限,和 maweiqing 所在的同一个 staff 组的用户拥有只读权限,剩余用户同样。

如果你想要知道命令的参数、输入输出信息,或者是想要了解它们的工作方式,可以试试 man 这个命令。它会接受一个程序名作为参数,然后将它的文档(用户手册)展现出来。

man ls

可以按 q 键退出用户手册。你可以趁机学习一下 mv(用于重命名或移动文件)、 cp(拷贝文件)以及 mkdir(新建文件夹)这些常用命令。注意,rm (删除文件)这个命令一定要慎用啊,搞不好就是删库跑路的节奏!

在 Shell 中,程序主要有两个流:输入流和输出流。当程序尝试读取信息时,就从输入流中读取;当程序尝试打印信息时,就将信息输出到输出流中。通常来说,键盘作为输入设备,显示器作为输出设备。

可以使用 <> 来重定向输入输出流。使用 >> 将输出以追加的方式重定向到文件。

➜  itwanger echo hello > hello.txt
➜  itwanger cat hello.txt
hello
➜  itwanger cat < hello.txt 
hello
➜  itwanger cat < hello.txt > hello1.txt
➜  itwanger cat hello1.txt 
hello
➜  itwanger echo world >> hello.txt 
➜  itwanger cat hello.txt 
hello
world

对于 Java 程序员来说,我们通常需要在运行环境上这样运行 jar 文件。& 代表在后台运行。

nohup java -jar XXX.jar > out.log &

对于绝大多数的类 Unix 系统,有一类用户非常特殊,就是 root 用户,可以创建、读取、更新和删除系统中的任何文件。

Unix 于 1969 年由贝尔实验室开发,目前主流的 Unix 系统有三种,分别是 AIX、HP-UX、Solaris,互不兼容。Linux 于 1991 年由芬兰大学生 Linus 开发,是一个类 Unix 系统,但是其代码不源自任何 Unix 版本,完全不是 Unix 的一个分支。

通常来说,我们并不会用 root 用户直接登录系统,因为这样可能会因为某些错误破坏系统。所以在需要的时候,我们会使用 sudo 命令,也就是以 su(super user)的身份去执行一些操作。

当你遇到 permission denied(拒绝访问)的错误时,通常是因为需要是 root 用户才能操作的原因引起的。get 了吧?

学到这,你掌握的 Shell 知识已经可以完成一些基础的任务了。有云服务器的同学,或者安装了虚拟机的同学,可以在上面建个临时文件夹练习下文中提到的命令。

(转载本站文章请注明作者和出处 沉默王二

Show Disqus Comments

Post Directory