第一章:Linux 简介

1.1 初识 Linux

与大家熟知的 Windows 操作系统软件一样,Linux 也是一个操作系统软件,其 logo 是一只企鹅(如图 1 所示)。与 Windows 不同之处在于,Linux 是一套开放源代码程序的、可以自由传播的类 Unix 操作系统软件。
image.png
Unix 系统是 Linux 系统的前身,具备很多优秀特性。
Linux 在设计之初,就是基于 Intel x86 系列 CPU 架构计算机的,它是一个基于 POSIX 的多用户、多任务并且支持多线程和多 CPU 的操作系统,它是由世界各地成千上万的程序员设计和开发实现的,当初开发 Linux 系统的目的就是建立不受任何商业化软件版权制约的、全世界都能自由使用的类 Unix 操作系统兼容产品。
在过去的 20 年里,Linux 系统主要被应用于服务器端、嵌入式开发和 PC 桌面 3 大领域,其中服务器端领域是重中之重。例如,我们熟知的大型、超大型互联网企业(百度、腾讯、Sina、阿里等)都在使用 Linux 系统作为其服务器端的程序运行平台,全球及国内排名前 1000 的 90% 以上的网站使用的主流系统都是 Linux 系统。

1.1.1 Linux 的发行版

Linux 有上百种不同的发行版, Linux 的发行版说简单点就是将 Linux 内核与应用软件做一个打包。目前市面上较知名的发行版有:Ubuntu、RedHat、CentOS、Debian、Fedora、SuSE、OpenSUSE、TurboLinux、BluePoint、RedFlag、Xterm、SlackWare等。

1.1.2 Linux 的特点

从上面的内容可以看出,Linux 操作系统之所以如此流行,是因为它具备如下这些优秀的特点:

  • Linux 不仅是免费的,更是开源的,这意味着任何人都可以获得其代码并根据自己的需求进行修改。
  • Linux 与 Unix 系统兼容,该系统的构建采用了一些与 UNIX 操作系统相同的技术,具备 Unix 几乎所有的优秀特性(系统的稳定性和安全性尤为突出)。
  • 和其他操作系统相比,Linux 更容易安装,且不会收到任何商业化版本的制约。
  • Linux 让开展各种实际有用且具有创造性的事情成为可能。例如,我们可以在一个U盘上装载 Linux 的自生系统引导映像(live boot image),启动一台硬盘已经崩溃的计算机,之后查找并解决该问题。或者,因为 Linux 是一个真正的多用户操作系统,它具有非常好的私密性和稳定性,整个团队可以同时从本地或远程登录进行工作。
  • Linux 提供了复杂的软件包管理系统,可以放心地安装和维护每一个在线资源库中的软件应用。

当然, Linux 操作系统的特点还有很多,这里不再过多赘述,相信随着学习 Linux 的深入,你会有更多的体会。

第二章:Linux 的安装

2.1 安装虚拟机

本小节是 Windows 用户提供,Mac 用户也可参考相应的软件进行安装,如果不需要,可以跳过本小节。
许多新手连 Windows 的安装都不太熟悉,更别提 Linux 的安装了;即使安装成功了,也有可能破坏现有的 Windows 系统,比如导致硬盘数据丢失、Windows 无法开机等。所以一直以来,安装 Linux 系统都是初学者的噩梦。
然而,通过虚拟机技术很容易冲破这种困境。由于虚拟机安装 Linux 所有的操作(例如硬盘分区、删除或修改数据)都是在虚拟硬盘中进行,因此不会对现有的数据和系统造成任何损失,即使安装失败了也无所谓。

2.1.1 什么是虚拟机

简单地说,虚拟机(Virtual Machine)就是允许我们在当前操作系统中运行其他操作系统的软件,本质上和 VS、QQ 这些应用程序一样,是通过软件技术虚拟出来的一台计算机,它在使用层面和真实的计算机并没有什么区别。
所以,只要我们在电脑(PC 或笔记本等)上安装好虚拟机软件,就可以模拟出来若干台相互独立的虚拟 PC 设备,每一个都如同一台真实的计算机。在此基础上,我们可以给每台虚拟的 PC 设备安装指定的操作系统,这样就可以实现在一台电脑上同时运行多个操作系统。
常见的虚拟机软件有 VMware Workstation(简称 VMware)、VirtualBox、Microsoft Virtual PC 等,其中 VMware 市场占有率最高,所以本小节以 VMware 为例来讲解 Linux 的安装。
image.png
VMware 可以使你在一台计算机上同时运行多个操作系统,例如同时运行 Windows、Linux 和 Mac OS。在计算机上直接安装多个操作系统,同一个时刻只能运行一个操作系统,重启才可以切换;而 Vmware 可以同时运行多个操作系统,可以像 Windows 应用程序一样来回切换。
在虚拟机系统中,每一台虚拟产生的计算机都被称为“虚拟机”,而用来存储所有虚拟机的计算机则被称为“宿主机”。例如,你的 Windows 系统就是宿主机,而 VMware 安装的 Linux 则为虚拟机。

2.1.2 VMware 下载和安装

来到官网下载 Windows 版本 VMware 安装程序,如图所示选择合适版本的安装程序并下载,可能需要注册完账号下载:
image.png
这里可以挑选自己喜欢的版本进行下载。
下载后可以双击 exe 文件进行安装,按照正常的安装流程一直下一步到最终安装即可。
VMware Pro 为商业收费版,由于涉及版权问题,这里就不进行具体展示了。

2.2 安装 Linux 操作系统

通过前面的小节学习,我们已经对 Linux 操作系统有了简单的了解,同时也在 Windows 下安装了虚拟机软件 VMware ,那么本节课我们就介绍下如何使用虚拟机软件安装 Linux 操作系统。
通过第一小节的学习我们知道 Linux 有很多的发行版本,本小节以 CentOS 8 为例来介绍 Linux 操作系统的安装步骤。学习本小节之后你可以按照本小节的介绍步骤,安装其他的 Linux 操作系统,本小节的目的主要是学习如何在虚拟机中安装 Linux 操作系统,方便后面学习 Linux 相关基础知识。

2.2.1 下载 CentOS 镜像

来到 CentOS 官网下载 CentOS 操作系统 .iso 文件,这里可以选择阿里云的镜像文件:
image.png

2.2.2 创建新的虚拟机

打开安装好的 VMware 虚拟机,选择 创建新的虚拟机 :
image.png
选择勾选 自定义,点击 下一步,继续安装:
image.png
选择 Workstation 15.x,点击 下一步 继续安装:
image.png
选择 稍后安装操作系统 ,点击 下一步 继续安装:
image.png
选择 Linux,点击 下一步 继续安装:
image.png
填写虚拟机名称和安装操作系统的目录:
image.png
根据自己电脑配置情况自行选择虚拟机操作系统的 处理器数 和 内核数:
image.png
选择虚拟机操作系统的内存大小,使用默认值即可:
image.png
接下来选择 使用网络地址转换:
image.png
接下来选择 LSI Logic(L),点击 下一步 继续安装:
image.png
接下来选择 NVMe(V),点击 下一步 继续安装:
image.png
接下来选择 创建新虚拟磁盘 ,点击 下一步 继续安装:
image.png
接下来分配磁盘空间大小,点击 下一步 继续安装:
image.png
接下来指定磁盘文件自定义目录,点击 下一步 继续安装:
image.png
接下来点击 自定义硬件:
image.png
选择 新CD/DVD(IDE) ,然后勾选 使用ISO映像文件 ,点击 关闭 即可:
image.png
检查网络适配器是否为 NAT :
image.png
接下来点击 完成 继续安装:
image.png

2.2.3 打开新的虚拟机

接下来选择刚才的操作系统,点击 开启此虚拟机 :
image.png
进入界面之后,按 回车键 即可开始安装,并耐心等待:
image.png
Tips:按住 Ctrl + Alt 键即可释放你的鼠标。
接下来进入安装界面:选择 中文 和 简体中文 ,点击 继续 即可:
image.png
接下来点击 安装的目的地:
image.png
直接点击 完成 即可:
image.png
接下来点击 开始安装 继续安装:
image.png
接下来选择 根密码 设置操作系统密码:
image.png
如下图所示,填写 root 账户密码:
image.png
Tips:注意在输入密码的时候,观察键盘第一个指示灯是否熄灭,否则可能右侧的数字键盘部分不能输入。
等待操作系统安装完成,安装完成之后点击 重启 即可:
image.png
接下来点击如下图所示选项:
image.png
勾选 我同意许可协议,然后点击 完成 即可完成安装:
image.png

第三章:Linux 和 Shell

3.1 Shell 简介

3.1.1 什么是 Shell

现在我们使用的操作系统(Windows、Mac OS、Android、iOS 等)都是带图形界面的,简单直观,容易上手,对专业用户(程序员、网管等)和普通用户(家庭主妇、老年人等)都非常适用;计算机的普及离不开图形界面。
然而在计算机的早期并没有图形界面,我们只能通过一个一个地命令来控制计算机,这些命令有成百上千之多,且不说记住这些命令非常困难,每天面对没有任何色彩的“黑屏”本身就是一件枯燥的事情;这个时候的计算机还远远谈不上炫酷和普及,只有专业人员才能使用。
对于图形界面,用户点击某个图标就能启动某个程序;对于命令行,用户输入某个程序的名字(可以看做一个命令)就能启动某个程序。这两者的基本过程都是类似的,都需要查找程序在硬盘上的安装位置,然后将它们加载到内存运行。
换句话说,图形界面和命令行要达到的目的是一样的,都是让用户控制计算机。
然而,真正能够控制计算机硬件(CPU、内存、显示器等)的只有操作系统内核(Kernel),图形界面和命令行只是架设在用户和内核之间的一座桥梁。
由于安全、复杂、繁琐等原因,用户不能直接接触内核(也没有必要),需要另外再开发一个程序,让用户直接使用这个程序;该程序的作用就是接收用户的操作(点击图标、输入命令),并进行简单的处理,然后再传递给内核,这样用户就能间接地使用操作系统内核了。你看,在用户和内核之间增加一层“代理”,既能简化用户的操作,又能保障内核的安全,何乐不为呢?
用户界面和命令行就是这个另外开发的程序,就是这层“代理”。在Linux下,这个命令行程序叫做 Shell。
Shell 是一个应用程序,它连接了用户和 Linux 内核,让用户能够更加高效、安全、低成本地使用 Linux 内核,这就是 Shell 的本质。
Shell 本身并不是内核的一部分,它只是站在内核的基础上编写的一个应用程序,它和 QQ、迅雷、Firefox 等其它软件没有什么区别。然而 Shell 也有着它的特殊性,就是开机立马启动,并呈现在用户面前;用户通过 Shell 来使用 Linux,不启动 Shell 的话,用户就没办法使用 Linux。

3.1.2 Shell 是如何连接用户和内核的?

Shell 能够接收用户输入的命令,并对命令进行处理,处理完毕后再将结果反馈给用户,比如输出到显示器、写入到文件等,这就是大部分读者对 Shell 的认知。你看,我一直都在使用 Shell,哪有使用内核哦?我也没有看到 Shell 将我和内核连接起来呀?!
其实,Shell 程序本身的功能是很弱的,比如文件操作、输入输出、进程管理等都得依赖内核。我们运行一个命令,大部分情况下 Shell 都会去调用内核暴露出来的接口,这就是在使用内核,只是这个过程被 Shell 隐藏了起来,它自己在背后默默进行,我们看不到而已。
接口其实就是一个一个的函数,使用内核就是调用这些函数。这就是使用内核的全部内容了吗?嗯,是的!除了函数,你没有别的途径使用内核。
比如,我们都知道在 Shell 中输入 cat log.txt 命令就可以查看 log.txt 文件中的内容,然而,log.txt 放在磁盘的哪个位置?分成了几个数据块?在哪里开始?在哪里终止?如何操作探头读取它?这些底层细节 Shell 统统不知道的,它只能去调用内核提供的 open() 和 read() 函数,告诉内核我要读取 log.txt 文件,请帮助我,然后内核就乖乖地按照 Shell 的吩咐去读取文件了,并将读取到的文件内容交给 Shell,最后再由 Shell 呈现给用户(其实呈现到显示器上还得依赖内核)。整个过程中 Shell 就是一个“中间商”,它在用户和内核之间“倒卖”数据,只是用户不知道罢了。

3.1.3 Shell 连接其它程序

在 Shell 中输入的命令,有一部分是 Shell 本身自带的,这叫做内置命令;有一部分是其它的应用程序(一个程序就是一个命令),这叫做外部命令
Shell 本身支持的命令并不多,功能也有限,但是 Shell 可以调用其他的程序,每个程序就是一个命令,这使得 Shell 命令的数量可以无限扩展,其结果就是 Shell 的功能非常强大,完全能够胜任 Linux 的日常管理工作,如文本或字符串检索、文件的查找或创建、大规模软件的自动部署、更改系统设置、监控服务器性能、发送报警邮件、抓取网页内容、压缩文件等。
更加惊讶的是,Shell 还可以让多个外部程序发生连接,在它们之间很方便地传递数据,也就是把一个程序的输出结果传递给另一个程序作为输入。
大家所说的 Shell 强大,并不是 Shell 本身功能丰富,而是它擅长使用和组织其他的程序。Shell 就是一个领导者,这正是 Shell 的魅力所在。
可以将 Shell 在整个 Linux 系统中的地位描述成下图所示的样子。注意“用户”和“其它应用程序”是通过虚线连接的,因为用户启动 Linux 后直接面对的是 Shell,通过 Shell 才能运行其它的应用程序。
image.png

3.1.4 Shell 编程

Shell 并不是简单的堆砌命令,我们还可以在 Shell 中编程,这和使用 C++、C#、Java、Python 等常见的编程语言并没有什么两样。
Shell 虽然没有 C++、Java、Python 等强大,但也支持了基本的编程元素,例如:

  • if…else 选择结构,case…in 开关语句,for、while、until 循环;
  • 变量、数组、字符串、注释、加减乘除、逻辑运算等概念;
  • 函数,包括用户自定义的函数和内置函数(例如 printf、export、eval 等)。

站在这个角度讲,Shell 也是一种编程语言,它的编译器(解释器)是 Shell 这个程序。我们平时所说的 Shell,有时候是指连接用户和内核的这个程序,有时候又是指 Shell 编程。
Shell 主要用来开发一些实用的、自动化的小工具,而不是用来开发具有复杂业务逻辑的中大型软件,例如检测计算机的硬件参数、搭建 Web 运行环境、日志分析等,Shell 都非常合适。
使用 Shell 的熟练程度反映了用户对 Linux 的掌握程度,运维工程师、网络管理员、程序员都应该学习 Shell。
尤其是 Linux 运维工程师,Shell 更是必不可少的,是必须掌握的技能,它使得我们能够自动化地管理服务器集群,否则你就得一个一个地登录所有的服务器,对每一台服务器都进行相同的设置,而这些服务器可能有成百上千之多,会浪费大量的时间在重复性的工作上。

3.1.5 Shell 脚本语言

任何代码最终都要被“翻译”成二进制的形式才能在计算机中执行。
有的编程语言,如 C/C++、Pascal、Go语言、汇编等,必须在程序运行之前将所有代码都翻译成二进制形式,也就是生成可执行文件,用户拿到的是最终生成的可执行文件,看不到源码。
这个过程叫做编译(Compile),这样的编程语言叫做编译型语言,完成编译过程的软件叫做编译器(Compiler)。
而有的编程语言,如 Shell、JavaScript、Python、PHP 等,需要一边执行一边翻译,不会生成任何可执行文件,用户必须拿到源码才能运行程序。程序运行后会即时翻译,翻译完一部分执行一部分,不用等到所有代码都翻译完。
这个过程叫做解释,这样的编程语言叫做解释型语言或者脚本语言(Script),完成解释过程的软件叫做解释器。
编译型语言的优点是执行速度快、对硬件要求低、保密性好,适合开发操作系统、大型应用程序、数据库等。
脚本语言的优点是使用灵活、部署容易、跨平台性好,非常适合 Web 开发以及小工具的制作。
Shell 就是一种脚本语言,我们编写完源码后不用编译,直接运行源码即可。

3.2 Linux 命令基本格式

从本小节开始,我们暂时不会再见到图形界面了,因为对服务器来讲,图形界面会占用更多的系统资源,而且会安装更多的服务、开放更多的端口,这对服务器的稳定性和安全性都有负面影响。其实,服务器是一个连显示器都没有的家伙,要图形界面干十么?
说到这里,有很多人会很崩溃。笔者就经常听到抱怨 Linux 是落后于时代的老古董,就像笔者的白头发一样!但是,大家要理解,对服务器来讲,稳定性、可靠性、安全性才是最主要的。而简单易用不是服务器需要考虑的事情,所以学习 Linux,这些枯燥的命令是必须学习和记忆的内容。

3.2.1 命令提示符

登录系统后,第一眼看到的内容是:
**_[root__@localhost__ ~]__#_**
这就是 Linux 系统的命令提示符。那么,这个提示符的含义是什么呢?

  • []:这是提示符的分隔符号,没有特殊含义。
  • root:显示的是当前的登录用户,笔者现在使用的是 root 用户登录。
  • @:分隔符号,没有特殊含义。
  • localhost:当前系统的简写主机名(完整主机名是 localhost.localdomain)。
  • ~:代表用户当前所在的目录,此例中用户当前所在的目录是家目录。
  • :命令提示符,Linux 用这个符号标识登录的用户权限等级。如果是超级用户,提示符就是 #;如果是普通用户,提示符就是 $。

家目录(又称主目录)是什么? Linux 系统是纯字符界面,用户登录后,要有一个初始登录的位置,这个初始登录位置就称为用户的家:

  • 超级用户的家目录:/root。
  • 普通用户的家目录:/home/用户名。

用户在自己的家目录中拥有完整权限,所以我们也建议操作实验可以放在家目录中进行。我们切换一下用户所在目录,看看有什么效果。
**_[root__@localhost__ ~]__# cd /usr/local__ _**
**_[root__@localhost__ __local__]__#_**
仔细看,如果切换用户所在目录,那么命令提示符中的会变成用户当前所在目录的最后一个目录(不显示完整的所在目录 /usr/ local,只显示最后一个目录 local)。

3.2.2 命令的基本格式

接下来看看 Linux 命令的基本格式:
[root@localhost ~]# 命令[选项][参数]
命令格式中的 [] 代表可选项,也就是有些命令可以不写选项或参数,也能执行。那么,我们就用 Linux 中最常见的 ls 命令来解释一下命令的格式(有关 ls 命令的具体用法,后续章节会详细介绍)。如果按照命令的分类,那么 ls 命令应该属于目录操作命令。
**_[root__@localhost__ ~]__# ls__ _**
**_anaconda-ks.cfg install.__log__ install.__log__.syslog_**

1. 选项的作用

ls 命令之后不加选项和参数也能执行,不过只能执行最基本的功能,即显示当前目录下的文件名。那么加入一个选项,会出现什么结果?

  1. [root@localhost ~]# Is -l
  2. 总用量44
  3. -rw-------.1 root root 1207 1 14 18:18 anaconda-ks.cfg
  4. -rw-r--r--.1 root root 24772 1 14 18:17 install.log
  5. -rw-r--r--.1 root root 7690 1 14 18:17 install.log.syslog

如果加一个 -l 选项,则可以看到显示的内容明显增多了。-l 是长格式(long list)的意思,也就是显示文件的详细信息。至于 -l 选项的具体含义,我们稍后再详细讲解。可以看到选项的作用是调整命令功能。如果没有选项,那么命令只能执行最基本的功能;而一旦有选项,则可以显示更加丰富的数据。
Linux 的选项又分为短格式选项 -l 和长格式选项 —all。短格式选项是英文的简写,用一个减号调用,例如:
**_[root__@localhost__ ~]__# ls -l_**
而长格式选项是英文完整单词,一般用两个减号调用,例如:
**_[root__@localhost__ ~]__# ls --all_**
一般情况下,短格式选项是长格式选项的缩写,也就是一个短格式选项会有对应的长格式选项。当然也有例外,比如 ls 命令的短格式选项 -l 就没有对应的长格式选项。所以具体的命令选项可以通过后面我们要学习的帮助命令来进行査询。

2. 参数的作用

参数是命令的操作对象,一般文件、目录、用户和进程等可以作为参数被命令操作。例如:

  1. [root@localhost ~]# ls -l anaconda-ks.cfg
  2. -rw-------.1 root root 1207 1 14 18:18 anaconda-ks.cfg

但是为什么一开始 ls 命令可以省略参数?那是因为有默认参数。命令一般都需要加入参数,用于指定命令操作的对象是谁。如果可以省略参数,则一般都有默认参数。例如:

  1. [root@localhost ~]# ls
  2. anaconda-ks.cfg install.log install.log.syslog

这个 ls 命令后面没有指定参数,默认参数是当前所在位置,所以会显示当前目录下的文件名。

3.3 echo 命令:输出

学习一种编程语言,写的第一个脚本都是打印 Hello world!,我们也写一个 Hello world! 脚本用来学习一下 Shell 脚本的运行方式。
在写脚本之前,我们需要学习一下 Linux 的打印命令 echo。该命令格式如下:

3.3.1 语法格式

[root@localhost ~]# echo [选项] [输出内容]
选项:

  • -e:支持反斜线控制的字符转换(具体参见表 1)
  • -n:取消输出后行末的换行符号(内容输出后不换行) | 控制字符 | 作 用 | | —- | —- | | \\ | 输出\本身 | | \a | 输出警告音 | | \b | 退格键,也就是向左删除键 | | \c | 取消输出行末的换行符。和“-n”选项一致 | | \e | Esc键 | | \f | 换页符 | | \n | 换行符 | | \r | 回车键 | | \t | 制表符,也就是Tab键 | | \v | 垂直制表符 | | \Onnn | 按照八进制 ASCII 码表输出字符。其中 0 为数字 0,nnn 是三位八进制数 | | \xhh | 按照十六进制 ASCH 码表输出字符。其中 hh 是两位十六进制数 |

表 1 控制字符

3.3.2 参考实例

其实 echo 命令非常简单,命令的输出内容如果没有特殊含义,则原内容输出到屏幕;如果输出内容有特殊含义,则输出打印其含义。

例 1

**_[root__@localhost__ ~]__# echo __"www.lintcode.com"__ _**
**_# echo的内容就会打印到屏幕上__ _**
**_www.lintcode.com _**
**_[root__@localhost__ ~]__#_**
echo 命令就是这么简单,输出什么内容,这个内容就会打印到屏幕上。

例 2

**_[root__@localhost__ ~]__# echo -n __"www.lintcode.com"_**
**_ www.lintcode.com[root__@localhost__ ~]__#__ _**
**_# 如果加入了 __"-n"__ 选项,则在输出内容结束后,不会换行,直接显示新行的提示符_**
在 echo 命令中如果使用了 -e 选项,则可以支持控制字符,如上边的表 1 所示。

例 3

**_[root__@localhost__ ~]# echo -e __"a\tb\tc\nd\te\tf"_**
**_a b c _**
**_d e f _**
**_# 因为加入了制表符__"\t"__和换行符__"\n"__,所以会按照格式输出_**

例 4

**_[root__@localhost__ ~]# echo -e __"\0141\t\0142\t\0143\n\0144\t\0145\t\0146"__ _**
**_a b c _**
**_d e f _**
**_# 还是会输出上面的内容,不过是按照制__ASCII码输出的_**

例 5

**_[root@localhost ~]# echo -e "__\x__61__\t\x__62__\t\x__63__\n\x__64__\t\x__65__\t\x__66" _**
**_a b c _**
**_d e f _**
**_# 如果按照十六进制ASCII码同样可以输出_**

3.4 Linux 变量

3.4.1 定义变量

定义变量时,变量名不加美元符号 $,如:
**_[root__@localhost__ ~]__# your_name=__"www.lintcode.com"_**
注意,变量名和等号之间不能有空格,这可能和你熟悉的所有编程语言都不一样。同时,变量名的命名须遵循如下规则:

  • 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
  • 中间不能有空格,可以使用下划线 _。
  • 不能使用标点符号。
  • 不能使用 bash 里的关键字(可用 help 命令查看保留关键字)。

有效的变量名示例如下:
Lintcode
LD_LIBRARY_PATH
_var
var2
无效的变量命名:
?var=123
user*name=lintcode
除了显式地直接赋值,还可以用语句给变量赋值,如:
**_for__ __file__ __in__ __ls /etc__ _**
**_ # 或 _**
**_ __for__ __file__ __in__ $(__ls__ /etc) _**
以上语句将 /etc 下目录的文件名循环出来。

3.4.2 使用变量

使用一个定义过的变量,只要在变量名前面加美元符号即可,如:

实例

  1. [root@localhost ~]# your_name="www.lintcode.com"
  2. [root@localhost ~]# echo $your_name
  3. www.lintcode.com
  4. [root@localhost ~]# echo ${your_name}
  5. www.lintcode.com

变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界。
推荐给所有变量加上花括号,这是个好的编程习惯。

3.5 Linux 环境变量

3.5.1 什么是环境变量

在上一个小节中,我们学习了变量,变量是计算机系统用于保存可变值的数据类型,我们可以直接通过变量名称来提取到对应的变量值。在 Linux 系统中,环境变量是用来定义系统运行环境的一些参数,比如每个用户不同的家目录(HOME)、邮件存放位置(MAIL)等。
Tips:Linux 系统中环境变量的名称一般都是大写的,这是一种约定俗成的规范。
我们可以使用 env 命令来查看到 Linux 系统中所有的环境变量,执行命令如下:

  1. [root@localhost ~]# env
  2. ORBIT_SOCKETDIR=/tmp/orbit-root
  3. HOSTNAME=livecd.centos
  4. GIO_LAUNCHED_DESKTOP_FILE_PID=2065
  5. TERM=xterm
  6. SHELL=/bin/bash
  7. ......

3.5.2 环境变量的作用

Linux 系统能够正常运行并且为用户提供服务,需要数百个环境变量来协同工作,但是,我们没有必要逐一学习每个变量,这里给大家列举了 10 个非常重要的环境变量,如表 1 所示。

环境变量名称 作用
HOME 用户的主目录(也称家目录)
SHELL 用户使用的 Shell 解释器名称
PATH 定义命令行解释器搜索用户执行命令的路径
EDITOR 用户默认的文本解释器
RANDOM 生成一个随机数字
LANG 系统语言、语系名称
HISTSIZE 输出的历史命令记录条数
HISTFILESIZE 保存的历史命令记录条数

表 1 Linux系统中重要的 10 个环境变量
Linux 作为一个多用户多任务的操作系统,能够为每个用户提供独立的、合适的工作运行环境,因此,一个相同的环境变量会因为用户身份的不同而具有不同的值。
例如,使用下述命令来查看 HOME 变量在不同用户身份下都有哪些值:

  1. [root@localhost ~]# echo $HOME
  2. /root
  3. [root@localhost ~]# su - user1 <--切换到 user1 用户身份
  4. [user1@localhost ~]$ echo $HOME
  5. /home/user1

这里的 su 命令可以临时切换用户身份
其实,环境变量是由固定的变量名与用户或系统设置的变量值两部分组成的,我们完全可以自行创建环境变量来满足工作需求。例如,设置一个名称为 WORKDIR 的环境变量,方便用户更轻松地进入一个层次较深的目录,执行命令如下:

  1. [root@localhost ~]# mkdir /home/work1
  2. [root@localhost ~]# WORKDIR=/home/work1
  3. [root@localhost ~]# cd $WORKDIR
  4. [root@localhost work1]# pwd
  5. /home/work1

但是,这样的环境变量不具有全局性,作用范围也有限,默认情况下不能被其他用户使用。如果工作需要,可以使用 export 命令将其提升为全局环境变量,这样其他用户就可以使用它了:

  1. [root@localhost work1]# su user1 <-- 切换到 user1,发现无法使用 WORKDIR 自定义变量
  2. [user1@localhost ~]$ cd $WORKDIR
  3. [user1@localhost ~]$ echo $WORKDIR
  4. [user1@localhost ~]$ exit <--退出user1身份
  5. [root@localhost work1]# export WORKDIR
  6. [root@localhost work1]# su user1
  7. [user1@localhost ~]$ cd $WORKDIR
  8. [user1@localhost work1]$ pwd
  9. /home/work1

3.6 let 命令:计算

let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。let 命令和双小括号 (( )) 的用法是类似的,它们都是用来对整数进行运算。
Tips:和双小括号 (( )) 一样,let 命令也只能进行整数运算,不能对小数(浮点数)或者字符串进行运算。

3.6.1 语法格式

**_let __arg__ [__arg__ ...]_**
arg:要执行的表达式
表达式可以用单引号或者双引号包围起来,当表达式中含有 Shell 特殊字符(例如 |)时,则必须用双引号 “ “ 或者单引号 ‘ ‘ 将表达式包围起来。
let 命令支持一次性计算多个表达式,并且以最后一个表达式的值作为整个 let 命令的执行结果。对于多个表达式之间的分隔符 let 命令以空格来分隔多个表达式。
另外还要注意,对于类似 let x+y 这样的写法,Shell 虽然计算了 x+y 的值,但却将结果丢弃;若不想这样,可以使用 let sum=x+y 将 x+y 的结果保存在变量 sum 中。
另外,let 还支持一些特殊操作,例如:

  • 自加操作:let no++
  • 自减操作:let no—
  • 简写形式 let no+=10,let no-=20,分别等同于 let no=no+10,let no=no-20。

    3.6.2 参考实例

    计算 1 + 2 的结果并输出
    **_[root@localhost ~]#__let__ sum=__1__+__2__ [root@localhost ~]#echo $sum __3 _**

3.7 expr 命令:四则运算和字符串运算

本小节为大家介绍 Linux 系统下的 expr 命令,一款多功能计算器。

3.7.1 语法格式

**_expr__ 表达式_**

表达式说明:

  • 用空格隔开每个项;
  • 用反斜杠 \ 放在 shell 特定的字符前面;
  • 对包含空格和其他特殊字符的字符串要用引号括起来

expr 不仅有数字计算功能,其实它还具备操作字符串的能力。

运算 表达式 意义
match match STRING REGEXP STRING 中匹配 REGEXP 字符串并返回匹配字符串的长度
substr substr STRING POS LENGTH 从 POS 位置获取长度为 LENGTH 的字符串
index index STRING SUBSTR 杳找子字符串的起始位置
length length STRING 计算字符串的长度

表1 expr 的字符串运算

3.7.2 参考实例

1. 加法

**_[__roc__@roclinux ~]$ expr __10__ + __10__ __20_**

2. 减法

**_[__roc__@roclinux ~]$ expr __20__ - __10__ __10_**

3. 除法

**_[__roc__@roclinux ~]$ expr __20__ / __2__ __10_**

4. 乘法

**_[roc@roclinux ~]$ __expr__ __20__ * __2__ __expr__: syntax __error_**
请注意 属于特殊字符,需要用反斜杠转义
乘法的正确写法是:
`_[**roc@roclinux ~]$ expr 20** \
2 **40_`

5. 混合运算

**_[__roc__@roclinux ~]$ expr \( __10__ + __10__ \) \* __2__ + __100__ __140_**

6. 匹配字符串

匹配字符串的长度,若找不到则返回 0:
**_[roc__@roclinux__ ~]__$ __expr match __"123 456 789"__ __".*5"__ __6_**

7. 截取字符串

从指定位置处抓取子字符串:
**_[__roc__@roclinux ~]$ expr substr __" this is a test"__ __3__ __5__ __his__ i_**

8. 查找子字符串位置

[roc@roclinux ~]$ expr index “test for the game” “e” __2

9. 计算子字符串长度

**_[roc__@roclinux__ ~]__$ __expr length __"this is a test"__ __14_**

3.8 案例练习

2653 · 显示字符串(一)
2679 · 显示字符串(二)
2681 · 显示字符串(三)
2795 · 设置环境变量
2719 · 执行表达式
2740 · 表达式求值(一)
2742 · 表达式求值(二)
2743 · 表达式求值(三)