《Linux命令行与shell编程大全》第一部分知识笔记
第一部分 LInux命令行
第1章:初始Linux Shelll
- 什么是Linux
- Linux内核的组成
- 探索Linux桌面
- 了解Linux发行版
1.1 什么是Linux:
Linux划分为四个部分:
- Linux内核
- GNU工具
- 图形化桌面环境
- 应用软件
1.1.1探究Linux内核
Linux核心是内核。内核控制着计算机系统上的所有硬件和软件,在必要时分配硬件,并根据需要执行软件。
主要负责以下四种功能:
-
系统内存管理
管理物理内存,还要创建和管理虚拟内存。
内存被划分为许多块,称为page。并将所有page放在物理内存或交换空间。然后,内核会维护一个内存页面表,指明哪些页面位于物理内存内,哪些页面被换到了磁盘上。
一段时间未访问的pages赋值到交换区域(换出)--即时还有可用内存
-
软件程序管理
Linux操作系统将运行中的程序称为进程。内核创建了第一个进程(称为init进程)来启动系统上所有其他进程。当内核启动时,它会将init进程加载到虚拟内存中。内核在启动任何其他进程时,都会在虚拟内存中给新进程分配一块专有区域来存储该进程用到的数据和代码。
-
硬件设备管理
任何Linux系统需要与之通信的设备,都需要在内核代码中加入其驱动程序代码。驱动程序代码相当于应用程序和硬件设备的中间人,允许内核与设备之间交换数据。
两种方法插入设备驱动代码:
- 编译进内核的设备驱动代码
- 可插入内核的设备驱动模块
Linux设备文件:
- 字符型设备文件:处理数据时每次只能处理一个字符的设备。(大多数类型的调制解调器和终端)
- 块设备:处理数据时每次能处理大块数据的设备,比如硬盘。
- 网络设备:采用数据包发送和接受数据的设备,包括各种网卡和一个特殊的回环设备。这个回环设备允许LInux系统使用常见的网络编程协议同自身通信。
Linux为系统上的每个设备都创建一种称为节点的特殊文件。与设备的所有通信都通过设备节点完成。个节点都有唯一的数值对供Linux内核标识它。数值对包括一个主设备号和一个次设备号。类似的设备被划分到同样的主设备号下。次设备号用于标识主设备组下的某个特定设备
-
文件系统管理
不同于其他一些操作系统,Linux内核支持通过不同类型的文件系统从硬盘中读写数据。除了自有的诸多文件系统外,Linux还支持从其他操作系统(比如Microsoft Windows)采用的文件系统中读写数据。内核必须在编译时就加入对所有可能用到的文件系统的支持。
Linux内核采用虚拟文件系统(Virtual File System,VFS)作为和每个文件系统交互的接口。
这为Linux内核同任何类型文件系统通信提供了一个标准接口。当每个文件系统都被挂载和使用
时,VFS将信息都缓存在内存中。
1.1.2 GNU工具
GNU组织(GNU是GNU’s Not Unix的缩写)开发了一套完整的Unix工具,但没有可以运行它们的内核系统。
-
核心GNU工具
GNU项目的主旨在于为Unix系统管理员设计出一套类似于Unix的环境。这个目标促使该项目移植了很多常见的Unix系统命令行工具。
供Linux系统使用的这组核心工具被称为coreutils(core utilities)软件包。
GNU coreutils软件包由三部分构成:
- 处理文件的工具
- 操作文本的工具
- 管理进程的工具
-
shell
GNU/Linux shell是一种特殊的交互式工具。它为用户提供了启动程序、管理文件系统中的文件以及运行在Linux系统上的进程的途径。shell的核心是命令行提示符。命令行提示符是shell负责交互的部分。它允许你输入文本命令,然后解释命令,并在内核中执行。
Linux发行版默认Shell是bash shell
1.1.3 Linux桌面环境
-
X Window系统
X Window软件是直接和PC上的显卡及显示器打交道的底层程序。它控制着Linux程序如何在电脑上显示出漂亮的窗口和图形。
-
KDE桌面
KDE(K Desktop Environment,K桌面环境)最初于1996年作为开源项目发布。它会生成一个类似于Microsoft Windows的图形化桌面环境。
-
GNOME桌面
GNOME(the GNU Network Object Model Environment,GNU网络对象模型环境)是另一个流行的Linux桌面环境。GNOME于1999年首次发布,现已成为许多Linux发行版默认的桌面环境(不过用得最多的是Red Hat Linux)。
-
Unity桌面
Unity桌面得名于该项目的目标——为工作站、平板电脑以及移动设备提供一致的桌面体验。不管你是在工作站还是在手机上使用Ubuntu,Unity桌面的使用方式都是一样的。
1.2 Linux发行版
我们将完整的Linux系统包称为发行版。有很多不同的Linux发行版来满足可能存在的各种运算需求。大多数发行版是为某个特定用户群定制的,比如商业用户、多媒体爱好者、软件开发人员或者普通家庭用户。每个定制的发行版都包含了支持特定功能所需的各种软件包,比如为多媒体爱好者准备的音频和视频编辑软件,为软件开发人员准备的编译器和集成开发环境(IDE)。
不同的Linux发行版通常归类为3种:
- 完整的核心Linux发行版
- 特定用途的发行版
- LiveCD测试发行版
第2章:走进shell
访问命令行
通过Linux控制台中断访问CLI
通过图形化终端仿真器访问CLI
使用GNOME终端仿真器
使用Konsole终端仿真器
使用xterm终端仿真器
2.1 进入命令行
CLI:command line interface文本命令行界面,只接受文本输入,也只能显示文本和基本图形。
由于这些限制,输出设备并不需要多华丽。通常只需要一个简单的哑终端就可以使用Unix系统。所谓的哑终端无非就是利用通信电缆(一般是一条多线束的串行电缆)连接到Unix系统上的一台显示器和一个键盘。这种简单的组合可以轻松地向Unix系统中输入文本数据,并查看文本输出结果。
第3章:基本的bash shell
使用shell
bash手册
浏览文件系统
文件和目录列表
管理文件和目录
查看文件内容
3.2 shell提示符
默认bash shell提示符是美元符号($),这个符号表明shell在等待用户输入。
除了作为shell的入口,提示符还能够提供其他的辅助信息。在上面的两个例子中,提示符中显示了当前用户ID名christine。另外还包括系统名server01。
3.2 bash 手册
man命令用来访问存储在Linux系统上的手册页面
当使用man命令查看命令手册页的时候,这些手册页是由分页程序(pager)来显示的。分页程序是一种实用工具,能够逐页显示文本。可以通过点击空格键进行翻页,或是使用回车键逐行查看
读完了手册页,可以点击q键退出。
3.3 浏览文件系统
Linux将文件存储在单个目录结构中,这个目录被称为虚拟目录(virtual directory)。虚拟目录将安装在PC上的所有存储设备的文件路径纳入单个目录结构中。
Linux虚拟目录结构只包含一个称为根(root)目录的基础目录。根目录下的目录和文件会按照访问它们的目录路径一一列出,这点跟Windows类似。
Linux使用正斜线/ 而不是反斜线\在文件路径中划分目录
Linux虚拟目录中比较复杂的部分是它如何协调管理各个存储设备。在Linux PC上安装的第一块硬盘称为根驱动器。根驱动器包含了虚拟目录的核心,其他目录都是从那里开始构建的。
Linux会在根驱动器上创建一些特别的目录,我们称之为挂载点(mount point)。挂载点是虚拟目录中用于分配额外存储设备的目录。虚拟目录会让文件和目录出现在这些挂载点目录中,然而实际上它们却存储在另外一个驱动器中。
Linux文件系统是从Unix文件结构演进来的。
常见的目录名均基于文件系统层级标准(filesystem hierarchy standard,FHS)。很多Linux发行版都遵循了FHS。这样一来,你就能够在任何兼容FHS的Linux系统中轻而易举地查找文件。
cd命令:可接受单个参数destination,用于指定想切换到的目录名。如果没有cd命令指定目标路径,它将切换到用户主目录。
pwd命令:显示出shell会话的当前目录,这个目录为当前工作目录。
-
绝对路径:从根目录开始开头为'/'。目录的全名
-
相对路径:基于当前位置的目标文件路径。
两个特殊字符可以用于相对文件路径中:
- 单点符(.),表示当前目录
- 双点符(..),表示当前目录的父目录
3.5 文件和目录列表
ls命令最基本的形式会显示当前目录下的文件和目录.
在Linux上,隐藏文件通常是文件名以点号开始的文件。这些文件并没有在默认的ls命令输出中显示出来,因此我们称其为隐藏文件。
ls -a要把隐藏文件和普通文件及目录一起显示出来,就得用到-a参数。
-R递归选项,列出了当前目录下包含的子目录中的文件。
-l
过滤输出列表
ls命令还支持在命令行中定义过滤器。它会用过滤器来决定应该在输出中显示哪些文件或目录。
ls -l my_script
- (?) : 代表一个字符
- (*) :代表0或多个字符
在过滤器中使用星号和问号被称为文件扩展匹配(file globbing),指的是使用通配符进行模式匹配的过程。通配符正式的名称叫作元字符通配符(metacharacter wildcards)。除了星号和问号之外,还有更多的元字符通配符可用于文件扩展匹配。可以使用中括号。
3.6 处理文件
3.6.1 创建文件
touch命令创建空文件。touch命令创建了你指定的新文件,并将你的用户名作为文件的属主。
touch命令还可用来改变文件的修改时间。这个操作并不需要改变文件的内容。
ls -l --time=ation test_one默认显示修改时间,这条命令则会显示访问时间
3.6.2 复制文件
cp命令
cp source destination
当source和destination参数都是文件名时,cp命令将源文件复制成一个新文件,并且以destination命名。新文件就像全新的文件一样,有新的修改时间。
-R 迭代复制
3.6.4 制表键自动补全
制表键自动补全允许你在输入文件名或目录名时按一下制表键,让shell帮忙将内容补充完整。
3.6.5 连接文件
链接文件是Linux文件系统的一个优势。
如需要在系统上维护同一文件的两份或多份副本,除了保存多份单独的物理文件副本之外,还可以采用保存一份物理文件副本和多个虚拟副本的方法。这种虚拟的副本就称为链接。链接是目录中指向文件真实位置的占位符。
Linux两种类型的文件连接:
-
符号链接
文件或目录的inode编号是一个用于标识的唯一数字,这个数字由内核分配给文件系统中的每一个对象。要查看文件或目录的inode编号,可以给ls命令加入-i参数。
-
硬链接
硬链接会创建独立的虚拟文件,其中包含了原始文件的信息及位置。但是它们从根本上而言是同一个文件。引用硬链接文件等同于引用了源文件。要创建硬链接,原始文件也必须事先存在,只不过这次使用ln命令时不再需要加入额外的参数了
3.6.5 重命名文件
在Linux中,重命名文件称为移动(moving)。mv命令可以将文件和目录移动到另一个位置或重新命名
-i询问是否覆盖已存在文件。
3.6.6删除文件
bash shell中删除文件的命令是rm。
rm -i fall
bash shell中没有回收站或垃圾箱,文件一旦删除,就无法再找回。因此,在使用rm命令时,要养成总是加入-i参数的好习惯。
也可以使用通配符删除成组的文件。别忘了使用-i选项保护好自己的文件。
rm命令的另外一个特性是,如果要删除很多文件且不受提示符的打扰,可以用-f参数强制删除。
3.7 处理目录
3.7.1 创建目录
mkdir
要想同时创建多个目录和子目录,需要加入-p参数:
mkdir -p newdir/dir/file
mkdir命令的-p参数可以根据需要创建缺失的父目录。父目录是包含目录树中下一级目录的目录。
删除目录
rmdir
默认情况下,rmdir命令只删除空目录。
也可以在整个非空目录上使用rm命令。使用-r选项使得命令可以向下进入目录,删除其中的文件,然后再删除目录本身。
rm -rf命令既没有警告信息,也没有声音提示。这肯定是一个危险的工具,尤其是在拥有
超级用户权限的时候。
3.8 查看文件内容
Linux中有几个命令可以查看文件的内容,而不需要调用其他文本编辑器.
file命令是一个随手可得的便捷工具。它能够探测文件的内部,并决定文件是什么类型的:
file命令能够确定该程序编译时所面向的平台以及需要何种类型的库。如果你有从未知源处获得的二进制文件,这会是个非常有用的特性:
3.8.2查看整个文件
如果手头有一个很大的文本文件,你可能会想看看里面是什么内容。在Linux上有3个不同的命令可以完成这个任务。
-
cat命令
cat命令是显示文本文件中所有数据的得力工具。
-
more命令
cat命令的主要缺陷是:一旦运行,你就无法控制后面的操作。为了解决这个问题,开发人员编写了more命令。more命令会显示文本文件的内容,但会在显示每页数据之后停下来。
和在手册页中前后移动一样,你可以通过按空格键或回车键以逐行向前的方式浏览文本文件。浏览完之后,按q键退出。
-
less命令
从名字上看,它并不像more命令那样高级。但是,less命令的命名实际上是个文字游戏(从俗语“less is more”得来),它实为more命令的升级版。它提供了一些极为实用的特性,能够实现在文本文件中前后翻动,而且还有一些高级搜索功能。
3.8.3 查看部分文件
通常你要查看的数据要么在文本文件的开头,要么在文本文件的末尾。如果这些数据是在大
型文件的起始部分,那你就得等cat或more加载完整个文件之后才能看到。如果数据是在文件的
末尾(比如日志文件),那可能需要翻过成千上万行的文本才能到最后的内容。好在Linux有解决
这两个问题的专用命令
-
tail 命令
tail命令会显示文件最后几行的内容(文件的“尾部”)。默认情况下,它会显示文件的末
尾10行。
-
head命令
head命令,顾名思义,会显示文件开头那些行的内容。默认情况下,它会显示文件前10行
第4章:更多的bash shell命令
管理进程
获取磁盘统计信息
挂载新磁盘
排序数据
归档数据
4.1 检测程序
Linux系统管理员面临的最复杂的任务之一就是跟踪运行在系统中的程序——尤其是现在,图形化桌面集成了大量的应用来生成一个完整的桌面环境。
4.1.1 探测进程
ps命令,ps命令好比工具中的瑞士军刀,它能输出运行在系统上的所有程序的许多信息。
默认情况下,ps命令只会显示运行在当前控制台下的属于当前用户的进程。
Linux系统中使用的GNU ps命令支持3种不同类型的命令行参数:
-
Unix风格的参数,前面加单破折线;
-
BSD风格的参数,前面不加破折线;
优点:许多系统管理员都喜欢BSD风格的l参数。它能输出更详细的进程状态码(STAT列)。双字符状态码能比Unix风格输出的单字符状态码更清楚地表示进程的当前状态
-
GNU风格的长参数,前面加双破折线。、
优点:GNU长参数中一个着实让人
喜爱的功能就是--forest参数。它会显示进程的层级信息,并用ASCII字符绘出可爱的图表。
4.1.2 实时监测进程
ps命令虽然在收集运行在系统上的进程信息时非常有用,但也有不足之处:它只能显示某个特定时间点的信息。如果想观察那些频繁换进换出的内存的进程趋势,用ps命令就不方便了。
top命令:top命令跟ps命令相似,能够显示进程信息,但它是实时显示的。
输出解释:
-
第一部分是系统的概况:第一行显示了当前时间、系统的运行时间、登录的用户数以及系统的平均负载
-
第二行显示了进程概要信息——top命令的输出中将进程叫作任务(task):有多少进程处在运行、休眠、停止或是僵化状态(僵化状态是指进程完成了,但父进程没有响应)。
-
第三行显示了CPU的概要信息。top根据进程的属主(用户还是系统)和进程的状态(运行、空闲还是等待)将CPU利用率分成几类输出
-
紧跟其后的两行说明了系统内存的状态。第一行说的是系统的物理内存:总共有多少内存,当前用了多少,还有多少空闲。后一行说的是同样的信息,不过是针对系统交换空间(如果分配了的话)的状态而言的。
-
最后一部分显示了当前运行中的进程的详细列表,有些列跟ps命令的输出类似
4.1.3 结束进程
在Linux中,进程之间通过信号来通信。进程的信号就是预定义好的一个消息,进程能识别它并决定忽略还是作出反应。进程如何处理信号是由开发人员通过编程来决定的。大多数编写完善的程序都能接收和处理标准Unix进程信号。
-
kill命令
kill命令可通过进程ID(PID)给进程发信号。默认情况下,kill命令会向命令行中列出的全部PID发送一个TERM信号。遗憾的是,你只能用进程的PID而不能用命令名,所以kill命令有时并不好用。
要发送进程信号,你必须是进程的属主或登录为root用户。
TERM信号告诉进程可能的话就停止运行。
-s参数支持指定其他信号(用信号名或信号值)。
kill -s HUP 3940 -
killall命令
killall命令非常强大,它支持通过进程名而不是PID来结束进程。killall命令也支持通配符,这在系统因负载过大而变得很慢时很有用.
4.2 检测磁盘空间
不管运行的是简单的Linux台式机还是大型的Linux服务器,你都要知道还有多少空间可留给你的应用程序。
4.2.1 挂载存储媒体
Linux文件系统将所有的磁盘都并入一个虚拟目录下。在使用新的存储媒体之前,需要把它放到虚拟目录下。这项工作称为挂载(mounting)。
-
mount命令
Linux上用来挂载媒体的命令叫作mount。默认情况下,mount命令会输出当前系统上挂载的设备列表。
mount命令提供如下四部分信息:
-
媒体的设备文件名
-
媒体挂载到虚拟目录的挂载点
-
文件系统类型
-
已挂载媒体的访问状态
-
-
umount
从Linux系统上移除一个可移动设备时,不能直接从系统上移除,而应该先卸载。
umount命令的格式非常简单:
umount [directory | device ]umount命令支持通过设备文件或者是挂载点来指定要卸载的设备。如果有任何程序正在使用设备上的文件,系统就不会允许你卸载它:
4.2.2 使用df命令
时你需要知道在某个设备上还有多少磁盘空间。df命令可以让你很方便地查看所有已挂载磁盘的使用情况
df命令会显示每个有数据的已挂载文件系统。如你在前例中看到的,有些已挂载设备仅限系统内部使用。命令输出如下:
-
设备的设备文件位置;
-
能容纳多少个1024字节大小的块;
-
已用了多少个1024字节大小的块;
-
还有多少个1024字节大小的块可用;
-
已用空间所占的比例;
-
设备挂载到了哪个挂载点上。
4.2.3 使用du命令
通过df命令很容易发现哪个磁盘的存储空间快没了。系统管理员面临的下一个问题是,发生这种情况时要怎么办。
du命令可以显示某个特定目录(默认情况下是当前目录)的磁盘使用情况。这一方法可用来快速判断系统上某个目录下是不是有超大文件。
默认情况下,du命令会显示当前目录下所有的文件、目录和子目录的磁盘使用情况,它会以磁盘块为单位来表明每个文件或目录占用了多大存储空间。
4.3 处理数据文件
当你有大量数据时,通常很难处理这些信息及提取有用信息。正如在上节中学习的du命令,系统命令很容易输出过量的信息。
4.3.1 排序数据
-
sort默认情况下,sort命令按照会话指定的默认语言的排序规则对文本文件中的数据行排序。按字符串的形式进行排序
sort -n告诉sort命令把数字识别成数字而不是字符,并且按值排序。 -
sort -M按月排序。
4.3.2 搜索数据
grep
grep命令的命令行格式如下: grep [options] pattern [file]
grep命令会在输入或指定的文件中查找包含匹配指定模式的字符的行。
-
进行反向搜索(排除搜索):
grep -v t file1 -
显示匹配模式的行所在的行号
-n -
如果知道有多少行含有匹配模式,
-c -
如果指定多个匹配模式,
-e:$ grep -e t -e f file1
4.3.3 压缩数据
gzip软件包是GNU项目的产物,意在编写一个能够替代原先Unix中compress工具的免费版.
- gzip: 压缩
- gzcat:查看压缩过的文本文件的内容
- gunzip:解压文件
4.3.4归档数据
虽然zip命令能够很好地将数据压缩和归档进单个文件,但它不是Unix和Linux中的标准归档工具。目前,Unix和Linux上最广泛使用的归档工具是tar命令。
tar命令最开始是用来将文件写到磁带设备上归档的,然而它也能把输出写到文件里,这种用法在Linux上已经普遍用来归档数据了。
下面是tar命令的格式:`tar function [options] object1 object2 ...
首先,你可以用下列命令来创建一个归档文件:
tar -cvf test.tar test/ test2/ 创建了名为test.tar的归档命令,含有test和test2目录内容。
接着使用:
tar -tf test.tar列出tar文件test.tar的内容(但不提取文件)。
最后:
tar -xvf test.tar
通过这一命令从tar文件test.tar中提取内容。如果tar文件是从一个目录结构创建的,那整个目录结构都会在当前目录下重新创建
第5章:理解shell
本章讨论了复杂的交互式程序:GNU bash shell。其中包括理解shell进程及其关系,如何生成子shell,以及子shell与父shell的关系。还探究了那些能够创建子进程的命令和不能创建子进程的命令。
当用户登录终端的时候,通常会启动一个默认的交互式shell。系统究竟启动哪个shell,这取决于用户ID配置。一般这个shell都是/bin/bash。默认的系统shell(/bin/sh)用于系统shell脚本,如那些需要在系统启动时运行的脚本子shell可以利用bash命令来生成。当使用进程列表或coproc命令时也会产生子shell。将子shell运用在命令行中使得我们能够创造性地高效使用CLI。子shell还可以嵌套,生成子shell的子shell,子shell的子shell的子shell。创建子shell的代价可不低,因为还必须为子shell创建出一个全新的环境。
在最后,我们学习了两种不同类型的命令:内建命令和外部命令。外部命令会创建出一个包含全新环境的子进程,而内建命令则不会。相比之下,外部命令的使用成本更高。内建命令因为不需要创建新环境,所以更高效,不会受到环境变化的影响。shell、子shell、进程和衍生进程都会受到环境变量的影响。下一章,我们会探究环境变量的影响方式以及如何在不同的上下文中使用环境变量。
第6章:使用Linux环境变量
什么是环境变量
创建自己的局部变量
删除环境变量
默认shell环境变量
设置PATH环境变量
定位环境文件
数据变量
很多程序和脚本都通过环境变量来获取系统信息、存储临时数据和配置信息。
6.1 什么是环境变量
bash shell用一个叫作环境变量(environment variable)的特性来存储有关shell会话和工作环境的信息(这也是它们被称作环境变量的原因)。这项特性允许你在内存中存储数据,以便程序或shell中运行的脚本能够轻松访问到它们。这也是存储持久数据的一种简便方法。
bash shell中:
- 全局变量
- 局部变量
6.1.1 全局环境变量
全局环境变量对于shell会话和所有生成的子shell都是可见的。局部变量则只对创建它们的shell可见。这让全局环境变量对那些所创建的子shell需要获取父shell信息的程序来说非常有用。
系统环境变量基本上都是使用全大写字母,以区别于普通用户的环境变量。
查看全局变量: env/printenv
显示个别环境变量的值: printenv
echo显示变量的值:echo $HOME
在echo命令中,在变量名前加上$可不仅仅是要显示变量当前的值。它能够让变量作为命令行参数。
6.1.2 局部环境变量
局部环境变量只能在定义它们的进程中可见。尽管它们是局部的,但是和全局环境变量一样重要。
set命令会显示为某个特定进程设置的所有环境变量,包括局部变量、全局变量以及用户定义变量。
6.2 设置用户定义变量
6.2.1 设置局部用户自定义变量
一旦启动了bash shell(或者执行一个shell脚本),就能创建在这个shell进程内可见的局部变量了。
可以通过等号给环境变量赋值,值可以是数值或字符串。
变量名、等号和值之间没有空格,这一点非常重要。
6.2.2 设置全局环境变量
在设定全局环境变量的进程所创建的子进程中,该变量都是可见的。创建全局环境变量的方法是先创建一个局部环境变量,然后再把它导出到全局环境中。
export命令,变量名前面不需要加$。
修改子shell中全局环境变量并不会影响到父shell中该变量的值。
6.3 删除环境变量
可以用unset命令完成这个操作。在unset命令中引用环境变量时,记住不要使用$
$ echo $my_variable
I am Global now
$
$ unset my_variable
$
$ echo $my_variable
$
在涉及环境变量名时,什么时候该使用\(,什么时候不该使用\),实在让人摸不着头脑。记住一点就行了:如果要用到变量,使用\(;如果要操作变量,不使用\)。这条规则的一个例外就是使用printenv显示某个变量的值。
如果你是在子进程中删除了一个全局环境变量,这只对子进程有效。该全局环境变量在父进程中依然可用。
$ my_variable="I am Global now"
$
$ export my_variable
$
$ echo $my_variable
I am Global now
$
$ bash
$
$ echo $my_variable
I am Global now
$
$ unset my_variable
$
$ echo $my_variable
$ exit
exit
$
$ echo $my_variable
I am Global now
和修改变量一样,在子shell中删除全局变量后,你无法将效果反映到父shell中。
6.4 默认的shell环境变量
bash shell会用一些特定的环境变量来定义系统环境。这些变量在你的Linux系统上都已经设置好了,只管放心使用。bash shell源自当初的Unix Bourne shell,因此也保留了Unix Bourne shell里定义的那些环境变量。
除了默认的Bourne的环境变量,bash shell还提供一些自有的变量:
不是所有的默认环境变量都会在运行set命令时列出。尽管这些都是默认环境变量,但并不是每一个都必须有一个值。
6.5 设置PATH环境变量
当你在shell命令行界面中输入一个外部命令时(参见第5章),shell必须搜索系统来找到对应的程序。PATH环境变量定义了用于进行命令和程序查找的目录。
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:
/sbin:/bin:/usr/games:/usr/local/games
可以把新的搜索目录添加到现有的PATH环境变量中,无需从头定义。PATH中各个目录之间是用冒号分隔的。你只需引用原来的PATH值,然后再给这个字符串添加新目录就行了。可以参考下面的例子。
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:
/sbin:/bin:/usr/games:/usr/local/games
$
$ PATH=$PATH:/home/christine/Scripts
$
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/
games:/usr/local/games:/home/christine/Scripts
$
$ myprog
The factorial of 5 is 120.
$
如果希望子shell也能找到你的程序的位置,一定要记得把修改后的PATH环境变量导出。
程序员通常的办法是将单点符也加入PATH环境变量。该单点符代表当前目录
$ PATH=$PATH:.
$
$ cd /home/christine/Old_Scripts
$
$ myprog2
The factorial of 6 is 720
对PATH变量的修改只能持续到退出或重启系统。这种效果并不能一直持续。
6.6 定位系统环境变量
问题是怎样让环境变量的作用持久化。
在你登入Linux系统启动一个bash shell时,默认情况下bash会在几个文件中查找命令。这些文件叫作启动文件或环境文件。bash检查的启动文件取决于你启动bash shell的方式。启动bash shell有3种方式:
- 登录时作为默认登录shell
- 作为非登录shell的交互式shell
- 作为运行脚本的非交互shell
6.6.1 登录shell
当你登录Linux系统时,bash shell会作为登录shell启动。登录shell会从5个不同的启动文件里读取命令:
- /etc/profile
- $HOME/.bash_profile
- $HOME/.bashrc
- $HOME/.bash_login
- $HOME/.profile
-
/etc/profile文件
/etc/profile文件是系统上默认的bash shell的主启动文件。系统上的每个用户登录时都会执行
这个启动文件。
-
$HOME目录下的启动文件
剩下的启动文件都起着同一个作用:提供一个用户专属的启动文件来定义该用户所用到的环境变量。大多数Linux发行版只用这四个启动文件中的一到两个:
这四个文件都以点号开头,这说明它们是隐藏文件
记住,$HOME表示的是某个用户的主目录。它和波浪号(~)的作用一样。
6.6.2 交互式shell
如果你的bash shell不是登录系统时启动的(比如是在命令行提示符下敲入bash时启动),那么你启动的shell叫作交互式shell。交互式shell不会像登录shell一样运行,但它依然提供了命令行提示符来输入命令。
如果bash是作为交互式shell启动的,它就不会访问/etc/profile文件,只会检查用户HOME目录中的.bashrc文件。
.bashrc文件有两个作用:一是查看/etc目录下通用的bashrc文件,二是为用户提供一个定制自己的命令别名(参见第5章)和私有脚本函数(将在第17章中讲到)的地方。
6.6.3 非交互式shell
系统执行shell脚本时用的就是这种shell。不同的地方在于它没有命令行提示符。但是当你在系统上运行脚本时,也许希望能够运行一些特定启动的命令。
当shell启动一个非交互式shell进程时,它会检查这个环境变量来查看要执行的启动文件。如果有指定的文件,shell会执行该文件里的命令,这通常包括shell脚本变量设置。
6.6.4 环境变量持久化
对全局环境变量来说(Linux系统中所有用户都需要使用的变量),可能更倾向于将新的或修改过的变量设置放在/etc/profile文件中,但这可不是什么好主意。如果你升级了所用的发行版,这个文件也会跟着更新,那你所有定制过的变量设置可就都没有了
最好是在/etc/profile.d目录中创建一个以.sh结尾的文件。把所有新的或修改过的全局环境变量设置放在这个文件中。
在大多数发行版中,存储个人用户永久性bash shell变量的地方是\(HOME/.bashrc文件。但如果设置了BASH_ENV变量,那么记住,除非它指向的是\)HOME/.bashrc,否则你应该将非交互式shell的用户变量放在别的地方。
6.7 数组变量
环境变量有一个很酷的特性就是,它们可作为数组使用。数组是能够存储多个值的变量。这些值可以单独引用,也可以作为整个数组来引用
要给某个环境变量设置多个值,可以把值放在括号里,值与值之间用空格分隔。
$ mytest=(one two three four five)
$
只有数组的第一个值显示出来了。要引用一个单独的数组元素,就必须用代表它在数组中位置的数值索引值。索引值要用方括号括起来。
$ echo ${mytest[2]}
three
$
环境变量数组的索引值都是从零开始。这通常会带来一些困惑。
-
显示整个数组变量,用*号作为通配符
$ echo ${mytest[*]} one two three four five $ -
也可以改变某个索引值位置的值。
$ mytest[2]=seven $ $ echo ${mytest[*]} one two seven four five $ -
能用unset命令删除数组中的某个值.
$ unset mytest[2] $ $ echo ${mytest[*]} one two four five $ $ echo ${mytest[2]} $ echo ${mytest[3]} four $删除元素但是保留位置。
-
可以在unset命令后跟上数组名来删除整个数组。
$ unset mytest $ $ echo ${mytest[*]} $
第7章:理解Linux文件权限
理解Linux的安全性
解读文件权限
使用LInux组
缺乏乏安全性的系统不是完整的系统。系统中必须有一套能够保护文件免遭非授权用户浏览或修改的机制。Linux沿用了Unix文件权限的办法,即允许用户和组根据每个文件和目录的安全性设置来访问文件。本章将介绍如何在必要时利用Linux文件安全系统保护和共享数据。
7.1 Linux的安全性
Linux安全系统的核心是用户账户。每个能进入Linux系统的用户都会被分配唯一的用户账户。用户对系统中各种对象的访问权限取决于他们登录系统时用的账户。
权限是通过登录时分配的UID来跟踪的。登录系统的时候用的是用户名而不是UID,并关联一个对应密码。
Linux系统使用特定的文件和工具来跟踪和管理系统上的用户账户。在我们讨论文件权限之前,先来看一下Linux是怎样处理用户账户的。
7.1.1 /etc/passwd 文件
Linux系统使用一个专门的文件来将用户的登录名匹配到对应的UID值。这个文件就是
/etc/passwd文件,它包含了一些与用户有关的信息。
下面是Linux系统上典型的/etc/passwd文件的一个例子。
root用户账户是Linux系统的管理员,固定分配给它的UID是0。Linux系统会为各种各样的功能创建不同的用户账户,而这些账户并不是真的用户。这些账户叫作系统账户,是系统上运行的各种服务进程访问资源用的特殊账户。所有运行在后台的服务都需要用一个系统用户账户登录到Linux系统上。
在安全成为一个大问题之前,这些服务经常会用root账户登录。遗憾的是,如果有非授权的用户攻陷了这些服务中的一个,他立刻就能作为root用户进入系统。为了防止发生这种情况,现在运行在Linux服务器后台的几乎所有的服务都是用自己的账户登录。这样的话,即使有人攻入了某个服务,也无法访问整个系统。
/etc/passwd文件中还有很多用户登录名和UID之外的信息。/etc/passwd文件的字段包含了如下信息:
- 登录用户名
- 用户密码
- 用户账户的UID(数字)
- 组ID(GID)(数字)
- 账户的文本描述(称为备注字段)
- 用户HOME目录的位置
- 用户的默认shell
/etc/passwd文件中的密码字段都被设置成了x,这并不是说所有的用户账户都用相同的密码。在早期的Linux上,/etc/passwd文件里有加密后的用户密码。但鉴于很多程序都需要访问/etc/passwd文件获取用户信息,这就成了一个安全隐患。随着用来破解加密密码的工具的不断演进,用心不良的人开始忙于破解存储在/etc/passwd文件中的密码。Linux开发人员需要重新考虑这个策略。
现在,绝大多数Linux系统都将用户密码保存在另一个单独的文件中(叫作shadow文件,位置在/etc/shadow)。只有特定的程序(比如登录程序)才能访问这个文件。
7.1.2 /etc/shadow文件
/etc/shadow文件对Linux系统密码管理提供了更多的控制。只有root用户才能访问/etc/shadow文件,这让它比起/etc/passwd安全许多。
/etc/shadow文件为系统上的每个用户账户都保存了一条记录。记录就像下面这样:
rich:$1$.FfcK0ns$f1UgiyHQ25wrB/hykCn020:11627:0:99999:7:::
在/etc/shadow文件的每条记录中都有9个字段:
-
与/etc/passwd文件中的登录名字段对应的登录名
-
加密后的密码
-
自上次修改密码后过去的天数密码(自1970年1月1日开始计算)
-
多少天后才能更改密码
-
多少天后必须更改密码
-
密码过期前提前多少天提醒用户更改密码7.1 Linux 的安全性 127
-
密码过期后多少天禁用用户账户
-
用户账户被禁用的日期(用自1970年1月1日到当天的天数表示)
-
预留字段给将来使用
使用shadow密码系统后,Linux系统可以更好地控制用户密码。它可以控制用户多久更改一次密码,以及什么时候禁用该用户账户,如果密码未更新的话。
7.1.3 添加新用户
用来向Linux系统添加新用户的主要工具是useradd。这个命令简单快捷,可以一次性创建新用户账户及设置用户HOME目录结构。useradd命令使用系统的默认值以及命令行参数来设置用户账户。系统默认值被设置在/etc/default/useradd文件中。可以使用加入了-D选项的useradd命令查看所用Linux系统中的这些默认值。
# /usr/sbin/useradd -D
GROUP=100
HOME=/home
INACTIVE=-1
EXPIRE=
SHELL=/bin/bash
SKEL=/etc/skel
CREATE_MAIL_SPOOL=yes
#
在创建新用户时,如果你不在命令行中指定具体的值,useradd命令就会使用-D选项所显示的那些默认值。这个例子列出的默认值如下:
-
新用户会被添加到GID为100的公共组;
-
新用户的HOME目录将会位于/home/loginname;
-
新用户账户密码在过期后不会被禁用;
-
新用户账户未被设置过期日期;
-
新用户账户将bash shell作为默认shell;
-
系统会将/etc/skel目录下的内容复制到用户的HOME目录下;
-
系统为该用户账户在mail目录下创建一个用于接收邮件的文件。
要想在创建用户时改变默认值或默认行为,可以使用命令行参数.
你会发现,在创建新用户账户时使用命令行参数可以更改系统指定的默认值。但如果总需要修改某个值的话,最好还是修改一下系统的默认值。
可以在-D选项后跟上一个指定的值来修改系统默认的新用户设置。
# useradd -D -s /bin/tsch
# useradd -D
GROUP=100
HOME=/home
INACTIVE=-1
EXPIRE=
SHELL=/bin/tsch
SKEL=/etc/skel
CREATE_MAIL_SPOOL=yes
#
7.1.4 删除用户
如果你想从系统中删除用户,userdel可以满足这个需求。默认情况下,userdel命令会只删除/etc/passwd文件中的用户信息,而不会删除系统中属于该账户的任何文件。
如果加上-r参数,userdel会删除用户的HOME目录以及邮件目录。然而,系统上仍可能存有已删除用户的其他文件。这在有些环境中会造成问题。
7.1.5 修改用户
Linux提供了一些不同的工具来修改已有用户账户的信息。
-
usermod
usermod命令是用户账户修改工具中最强大的一个。它能用来修改/etc/passwd文件中的大部分字段,只需用与想修改的字段对应的命令行参数就可以了。参数大部分跟useradd命令的参数一样(比如,-c修改备注字段,-e修改过期日期,-g修改默认的登录组)。除此之外,还有另外一些可能派上用场的选项。
-
-l修改用户账户的登录名。
-
-L锁定账户,使用户无法登录。
-
-p修改账户的密码。
-
-U解除锁定,使用户能够登录。
-L选项尤其实用。它可以将账户锁定,使用户无法登录,同时无需删除账户和用户的数据。要让账户恢复正常,只要用-U选项就行了。
-
-
passwd和chpasswd
改变用户密码的一个简便方法就是用passwd命令。
# passwd test Changing password for user test. New UNIX password: Retype new UNIX password: passwd: all authentication tokens updated successfully. #如果只用passwd命令,它会改你自己的密码。系统上的任何用户都能改自己的密码,但只有root用户才有权限改别人的密码。
-e选项能强制用户下次登录时修改密码。你可以先给用户设置一个简单的密码,之后再强制在下次登录时改成他们能记住的更复杂的密码。
如果需要为系统中的大量用户修改密码,chpasswd命令可以事半功倍。chpasswd命令能从标准输入自动读取登录名和密码对(由冒号分割)列表,给密码加密,然后为用户账户设置。你也可以用重定向命令来将含有userid:passwd对的文件重定向给该命令。
-
chsh、chfn、chage
- chsh、chfn和chage工具专门用来修改特定的账户信息。chsh命令用来快速修改默认的用户登录shell。使用时必须用shell的全路径名作为参数,不能只用shell名。
# chsh -s /bin/csh test Changing shell for test. Shell changed. #-
chfn命令提供了在/etc/passwd文件的备注字段中存储信息的标准方法。chfn命令会将用于Unix的finger命令的信息存进备注字段,而不是简单地存入一些随机文本(比如名字或昵称之类的),或是将备注字段留空。finger命令可以非常方便地查看Linux系统上的用户信息。
# finger rich Login: rich Name: Rich Blum Directory: /home/rich Shell: /bin/bash On since Thu Sep 20 18:03 (EDT) on pts/0 from 192.168.1.2 No mail. No Plan. #如果在使用chfn命令时没有参数,它会向你询问要将哪些适合的内容加进备注字段。
# chfn test Changing finger information for test. Name []: Ima Test Office []: Director of Technology Office Phone []: (123)555-1234 Home Phone []: (123)555-9876 Finger information changed. # finger test Login: test Name: Ima Test Directory: /home/test Shell: /bin/csh Office: Director of THome Phone: (123)555-9876 Never logged in. No mail. No Plan.echnology Office Phone: (123)555-1234 -
chage命令用来帮助管理用户账户的有效期。你需要对每个值设置多个参数.
chage命令的日期值可以用下面两种方式中的任意一种:
-
YYYY-MM-DD格式的日期
-
代表从1970年1月1日起到该日期天数的数值
chage命令中有个好用的功能是设置账户的过期日期。有了它,你就能创建在特定日期自动过期的临时用户,再也不需要记住删除用户了!过期的账户跟锁定的账户很相似:账户仍然存在,但用户无法用它登录
-
7.2 使用Linux用户组
用户账户在控制单个用户安全性方面很好用,但涉及在共享资源的一组用户时就捉襟见肘了。为了解决这个问题,Linux系统采用了另外一个安全概念——组(group)
组权限允许多个用户对系统中的对象(比如文件、目录或设备等)共享一组共用的权限。每个组都有唯一的GID——跟UID类似,在系统上这是个唯一的数值。除了GID,每个组还有唯一的组名。Linux系统上有一些组工具可以创建和管理你自己的组。
7.2.1 /etc/group
与用户账户类似,组信息也保存在系统的一个文件中。/etc/group文件包含系统上用到的每个组的信息。
root:x:0:root
bin:x:1:root,bin,daemon
daemon:x:2:root,bin,daemon
sys:x:3:root,bin,adm
adm:x:4:root,adm,daemon
rich:x:500:
mama:x:501:
katie:x:502:
jessica:x:503:
mysql:x:27:
test:x:504:
和UID一样,GID在分配时也采用了特定的格式。系统账户用的组通常会分配低于500的GID值,而用户组的GID则会从500开始分配。/etc/group文件有4个字段:
- 组名
- 组密码
- GID属于该组的用户列表
7.2.2创建新组
groupadd命令可在系统上创建新组。
# /usr/sbin/groupadd shared
# tail /etc/group
haldaemon:xxfs:x:43:
gdm:x:42:
rich:x:500:
mama:x:501:
katie:x:502:
jessica:x:503:
mysql:x:27:
test:x:504:
shared:x:505::68:
#
在创建新组时,默认没有用户被分配到该组。groupadd命令没有提供将用户添加到组中的选项,但可以用usermod命令来弥补这一点。
# /usr/sbin/usermod -G shared rich
# /usr/sbin/usermod -G shared test
# tail /etc/group
haldaemon:x:68:
xfs:x:43:
gdm:x:42:
rich:x:500:
mama:x:501:
katie:x:502:
jessica:x:503:
mysql:x:27:
test:x:504:
shared:x:505:rich, test
#
7.2.3 修改组
shared组现在有两个成员:test和rich。usermod命令的-G选项会把这个新组添加到该用户账户的组列表里。
在/etc/group文件中可以看到,需要修改的组信息并不多。groupmod命令可以修改已有组的GID(加-g选项)或组名(加-n选项)。
# /usr/sbin/groupmod -n sharing shared
# tail /etc/group
haldaemon:x:68:
xfs:x:43:
gdm:x:42:
rich:x:500:
mama:x:501:
katie:x:502:
jessica:x:503:
mysql:x:27:
test:x:504:
sharing:x:505:test,rich
#
修改组名时,GID和组成员不会变,只有组名改变。由于所有的安全权限都是基于GID的,你可以随意改变组名而不会影响文件的安全性。
7.3 理解文件权限
7.3.1 使用文件权限符
ls命令可以用来查看Linux系统上的文件、目录和设备的权限。
$ ls –l
total 68
-rw-rw-r-- 1 rich rich 50 2010-09-13 07:49 file1.gz
-rw-rw-r-- 1 rich rich 23 2010-09-13 07:50 file2
-rw-rw-r-- 1 rich rich 48 2010-09-13 07:56 file3
-rw-rw-r-- 1 rich rich 34 2010-09-13 08:59 file4
-rwxrwxr-x 1 rich rich 4882 2010-09-18 13:58 myprog
-rw-rw-r-- 1 rich rich 237 2010-09-18 13:58 myprog.c
drwxrwxr-x 2 rich rich 4096 2010-09-03 15:12 test1
drwxrwxr-x 2 rich rich 4096 2010-09-03 15:12 test2
$
输出结果的第一个字段就是描述文件和目录权限的编码。这个字段的第一个字符代表了对象的类型:
-
-代表文件
-
d代表目录
-
l代表链接
-
c代表字符型设备
-
b代表块设备
-
n代表网络设备
之后有3组三字符的编码。每一组定义了3种访问权限:
-
r代表对象是可读的
-
w代表对象是可写的
-
x代表对象是可执行的
若没有某种权限,在该权限位会出现单破折线。这3组权限分别对应对象的3个安全级别:
-
对象的属主
-
对象的属组
-
系统其他用户
-rwxrwxr-x 1 rich rich 4882 2010-09-18 13:58 myprog
文件myprog下有三组权限:
- rwx:文件属主读写执行(设为登录名rich)
- rwx:属组成员读写执行(设为组名rich)
- r-x:其它用户读执行(系统上其它人)
7.3.2 默认文件权限
umask命令用来设置所创建文件和目录的默认权限。
touch命令用分配给我的用户账户的默认权限创建了这个文件。umask命令可以显示和设置这个默认权限。
$ umask
0022
$
第一位代表了一项特别的安全特性,叫作粘着位(sticky bit)。
后面的3位表示文件或目录对应的umask八进制值。要理解umask是怎么工作的,得先理解八进制模式的安全性设置。
八进制模式的安全性设置先获取这3个rwx权限的值,然后将其转换成3位二进制值,用一个八进制值来表示。在这个二进制表示中,每个位置代表一个二进制位。因此,如果读权限是唯一置位的权限,权限值就是r--,转换成二进制值就是100,代表的八进制值是4。表7-5列出了可能会遇到的组合。
八进制模式先取得权限的八进制值,然后再把这三组安全级别(属主、属组和其他用户)的八进制值顺序列出。因此,八进制模式的值664代表属主和属组成员都有读取和写入的权限,而其他用户都只有读取权限。
umask值只是个掩码。它会屏蔽掉不想授予该安全级别的权限。接下来我们还得再多进行一些八进制运算才能搞明白来龙去脉。
要把umask值从对象的全权限值中减掉。对文件来说,全权限的值是666(所有用户都有读和写的权限);而对目录来说,则是777(所有用户都有读、写、执行权限)。
所以在上例中,文件一开始的权限是666,减去umask值022之后,剩下的文件权限就成了644。
7.4 改变安全性设置
如果你已经创建了一个目录或文件,需要改变它的安全性设置,在Linux系统上有一些工具
能够完成这项任务。
7.4.1 改变权限
chmod命令用来改变文件和目录的安全性设置。该命令的格式如下:
chmod options mode file
mode参数可以使用八进制模式或符号模式进行安全性设置。八进制模式设置非常直观,直接用期望赋予文件的标准3位八进制权限码即可。
$ chmod 760 newfile
$ ls -l newfile
-rwxrw---- 1 rich rich 0 Sep 20 19:16 newfile
$
八进制文件权限会自动应用到指定的文件上。符号模式的权限就没这么简单了。
[ugoa…][[+-=][rwxXstugo…]
第一组字符定义了权限作用的对象:
-
u代表用户
-
g代表组
-
o代表其他
-
a代表上述所有
下一步,后面跟着的符号表示你是想在现有权限基础上增加权限(+),还是在现有权限基础上移除权限(-),或是将权限设置成后面的值(=)。
最后,第三个符号代表作用到设置上的权限。你会发现,这个值要比通常的rwx多。额外的设置有以下几项。
像这样使用这些权限:
$ chmod o+r newfile
$ ls -lF newfile
-rwxrw-r-- 1 rich rich 0 Sep 20 19:16 newfile*
$
7.4.2 改变所属关系
有时你需要改变文件的属主,比如有人离职或开发人员创建了一个在产品环境中需要归属在系统账户下的应用。Linux提供了两个命令来实现这个功能:chown命令用来改变文件的属主,chgrp命令用来改变文件的默认属组
-
chown命令的格式如下:
chown options owner[.group] file# chown dan newfile # ls -l newfile -rw-rw-r-- 1 dan rich 0 Sep 20 19:16 newfile #非常简单。chown命令也支持同时改变文件的属主和属组。
# chown dan.shared newfile # ls -l newfile -rw-rw-r-- 1 dan shared 0 Sep 20 19:16 newfile # -
chgrp命令可以更改文件或目录的默认属组。
$ chgrp shared newfile $ ls -l newfile -rw-rw-r-- 1 rich shared 0 Sep 20 19:16 newfile $
7.5 共享文件
Linux系统上共享文件的方法是创建组。但在一个完整的共享文件的环境中,事情会复杂得多。
创建新文件时,Linux会用你默认的UID和GID给文件分配权限。想让其他人也能访问文件,要么改变其他用户所在安全组的访问权限,要么就给文件分配一个包含其他用户的新默认属组.
Linux还为每个文件和目录存储了3个额外的信息位。
-
设置用户ID(SUID):当文件被用户使用时,程序会以文件属主的权限运行。
-
设置组ID(SGID):对文件来说,程序会以文件属组的权限运行;对目录来说,目录中
创建的新文件会以目录的默认属组作为默认属组。
-
黏着位:进程结束后文件还驻留(粘着)在内存中。
SGID位对文件共享非常重要。启用SGID位后,你可以强制在一个共享目录下创建的新文件都属于该目录的属组,这个组也就成为了每个用户的属组。
因此,要创建一个共享目录,使目录里的新文件都能沿用目录的属组,只需将该目录的SGID位置位。
$ mkdir testdir
$ ls -l
drwxrwxr-x 2 rich rich 4096 Sep 20 23:12 testdir/
$ chgrp shared testdir
$ chmod g+s testdir
$ ls -l
drwxrwsr-x 2 rich shared 4096 Sep 20 23:12 testdir/
$ umask 002
$ cd testdir
$ touch testfile
$ ls -l
total 0
-rw-rw-r-- 1 rich shared 0 Sep 20 23:13 testfile
$
首先,用mkdir命令来创建希望共享的目录。然后通过chgrp命令将目录的默认属组改为包含所有需要共享文件的用户的组(你必须是该组的成员)。最后,将目录的SGID位置位,以保证目录中新建文件都用shared作为默认属组。
为了让这个环境能正常工作,所有组成员都需把他们的umask值设置成文件对属组成员可写。在前面的例子中,umask改成了002,所以文件对属组是可写的。
做完了这些,组成员就能到共享目录下创建新文件了。跟期望的一样,新文件会沿用目录的属组,而不是用户的默认属组。现在shared组的所有用户都能访问这个文件了。
第8章:管理文件系统
文件系统基础
日志文件与写时复制文件系统
文件系统管理
逻辑卷布局
使用Linux逻辑卷管理器
8.1 探索Linux文件系统
Linux支持多种类型的文件系统管理文件和目录。每种文件系统都在存储设备上实现了虚拟目录结构,仅特性略有不同
8.1.1 基本的Linux文件系统
Linux最初采用的是一种简单的文件系统,它模仿了Unix文件系统的功能。
-
ext文件系统
Linux操作系统中引入的最早的文件系统叫作扩展文件系统(extended filesystem,简记为ext)。
它为Linux提供了一个基本的类Unix文件系统:使用虚拟目录来操作硬件设备,在物理设备上按定长的块来存储数据。
ext文件系统采用名为索引节点的系统来存放虚拟目录中所存储文件的信息。索引节点系统在每个物理设备中创建一个单独的表(称为索引节点表)来存储这些文件的信息。存储在虚拟目录中的每一个文件在索引节点表中都有一个条目。ext文件系统名称中的extended部分来自其跟踪的每个文件的额外数据,包括:
- 文件名
- 文件大小
- 文件属主
- 文件的属组
- 文件的访问权限
- 指向存有文件数据的每个硬盘块的指针
Linux通过唯一的数值(称作索引节点号)来引用索引节点表中的每个索引节点,这个值是创建文件时由文件系统分配的。文件系统通过索引节点号而不是文件全名及路径来标识文件。
-
ext2文件系统
最早的ext文件系统有不少限制,比如文件大小不得超过2 GB。在Linux出现后不久,ext文件系统就升级到了第二代扩展文件系统,叫作ext2
ext2文件系统扩展了索引节点表的格式来保存系统上每个文件的更多信息。
ext2的索引节点表为文件添加了创建时间值、修改时间值和最后访问时间值来帮助系统管理员追踪文件的访问情况。ext2文件系统还将允许的最大文件大小增加到了2 TB(在ext2的后期版本中增加到了32 TB),以容纳数据库服务器中常见的大文件。
除了扩展索引节点表外,ext2文件系统还改变了文件在数据块中存储的方式。ext文件系统常见的问题是在文件写入到物理设备时,存储数据用的块很容易分散在整个设备中(称作碎片化,fragmentation)。数据块的碎片化会降低文件系统的性能,因为需要更长的时间在存储设备中查找特定文件的所有块。
保存文件时,ext2文件系统通过按组分配磁盘块来减轻碎片化。通过将数据块分组,文件系统在读取文件时不需要为了数据块查找整个物理设备。
ext2文件系统由于容易在系统崩溃或断电时损坏而臭名昭著。即使文件数据正常保存到了物理设备上,如果索引节点表记录没完成更新的话,ext2文件系统甚至都不知道那个文件存在!
8.1.2 日志文件系统
日志文件系统为Linux系统增加了一层安全性。它不再使用之前先将数据直接写入存储设备再更新索引节点表的做法,而是先将文件的更改写入到临时文件(称作日志,journal)中。在数据成功写到存储设备和索引节点表之后,再删除对应的日志条目。
如果系统在数据被写入存储设备之前崩溃或断电了,日志文件系统下次会读取日志文件并处理上次留下的未写入的数据。
Linux3种广泛使用的日志方法,每个保护等级都不同:
数据模式日志方法是目前为止最安全的数据保护方法,但同时也是最慢的。所有写到存储设备上的数据都必须写两次:第一次写入日志,第二次写入真正的存储设备。这样会导致性能很差,尤其是对要做大量数据写入的系统而言
-
ext3 文件系统
它采用和ext2文件系统相同的索引节点表结构,但给每个存储设备增加了一个日志文件,以将准备写入存储设备的数据先记入日志。
ext3文件系统无法恢复误删的文件,它没有任何内建的数据压缩功能(虽然有个需单独安装的补
丁支持这个功能),ext3文件系统也不支持加密文件。
-
ext4 文件系统
现在已是大多数流行的Linux发行版采用的默认文件系统,比如Ubuntu。
除了支持数据压缩和加密,ext4文件系统还支持一个称作区段(extent)的特性。区段在存储
设备上按块分配空间,但在索引节点表中只保存起始块的位置。由于无需列出所有用来存储文件中数据的数据块,它可以在索引节点表中节省一些空间。
ext4还引入了块预分配技术(block preallocation)。如果你想在存储设备上给一个你知道要变大的文件预留空间,ext4文件系统可以为文件分配所有需要用到的块,而不仅仅是那些现在已经用到的块。ext4文件系统用0填满预留的数据块,不会将它们分配给其他文件。
-
Reiser文件系统
ReiserFS文件系统只支持回写日志模式——只把索引节点表数据写到日志文件。ReiserFS文件系统也因此成为Linux上最快的日志文件系统之一。
有两个有意思的特性被引入了ReiserFS文件系统:一个是你可以在线调整已有文件系统的大小;另一个是被称作尾部压缩(tailpacking)的技术,该技术能将一个文件的数据填进另一个文件的数据块中的空白空间。如果你必须为已有文件系统扩容来容纳更多的数据,在线调整文件系统大小功能非常好用。
-
JFS文件系统
JFS(Journaled File System,日志化文件系统①)是IBM在1990年为其Unix衍生版AIX开发的
JFS文件系统采用的是有序日志方法,即只在日志中保存索引节点表数据,直到真正的文件数据被写进存储设备时才删除它。这个方法在ReiserFS的速度和数据模式日志方法的完整性之间的采取的一种折中。
JFS文件系统采用基于区段的文件分配,即为每个写入存储设备的文件分配一组块。这样可以减少存储设备上的碎片。
-
XFS文件系统
美国
硅图公司(SGI)最初在1994年为其商业化的IRIX Unix系统开发了XFS。XFS文件系统采用回写模式的日志,在提供了高性能的同时也引入了一定的风险,因为实际数据并未存进日志文件。XFS文件系统还允许在线调整文件系统的大小,这点类似于ReiserFS文件系统,除了XFS文件系统只能扩大不能缩小
8.1.3 写时复制文件系统
采用了日志式技术,你就必须在安全性和性能之间做出选择。尽管数据模式日志提供了最高的安全性,但是会对性能带来影响,因为索引节点和数据都需要被日志化。如果是回写模式日志,性能倒是可以接受,但安全性就会受到损害。
就文件系统而言,日志式的另一种选择是一种叫作写时复制(copy-on-write,COW)的技术。
COW利用快照兼顾了安全性和性能。如果要修改数据,会使用克隆或可写快照。修改过的数据并不会直接覆盖当前数据,而是被放入文件系统中的另一个位置上。即便是数据修改已经完成,之前的旧数据也不会被重写。
-
ZFS文件系统
ZFS是一个稳定的文件系统,与Resier4、Btrfs和ext4势均力敌。它最大的弱项就是没有使用GPL许可。
-
Btrf文件系统
Btrfs文件系统是COW的新人,也被称为B树文件系统。它是由Oracle公司于2007年开始研发的。Btrfs在Reiser4的诸多特性的基础上改进了可靠性。另一些开发人员最终也加入了开发过程,帮助Btrfs快速成为了最流行的文件系统。究其原因,则要归于它的稳定性、易用性以及能够动态调整已挂载文件系统的大小。OpenSUSE Linux发行版最近将Btrfs作为其默认文件系统。除此之外,该文件系统也出现在了其他Linux发行版中(如RHEL),不过并不是作为默认文件系统。
8.2 操作文件系统
8.2.1 创建分区
一开始,你必须在存储设备上创建分区来容纳文件系统。分区可以是整个硬盘,也可以是部分硬盘,以容纳虚拟目录的一部分。
fdisk工具用来帮助管理安装在系统上的任何存储设备上的分区。它是个交互式程序,允许你输入命令来逐步完成硬盘分区操作。
要启动fdisk命令,你必须指定要分区的存储设备的设备名,另外还得有超级用户权限。
$ sudo fdisk /dev/sdb
[sudo] password for Christine:
Device contains neither a valid DOS partition table,
nor Sun, SGI or OSF disklabel
Building a new DOS disklabel with disk identifier 0xd3f759b5.
Changes will remain in memory only
until you decide to write them.
After that, of course, the previous content won't be recoverable.
Warning: invalid flag 0x0000 of partition table 4 will
be corrected by w(rite)
[...]
Command (m for help):
fdisk交互式命令提示符使用单字母命令来告诉fdisk做什么.
尽管看上去很恐怖,但实际上你在日常工作中用到的只有几个基本命令。
-
p将一个存储设备的详细信息显示出来 -
n创建新的分区Command (m for help): n Command action e extended p primary partition (1-4) p Partition number (1-4): 1 First cylinder (1-652, default 1): 1 Last cylinder, +cylinders or +size{K,M,G} (1-652, default 652): +2G Command (m for help):分区可以按主分区(primary partition)或扩展分区(extended partition)创建。主分区可以被文件系统直接格式化,而扩展分区则只能容纳其他主分区①。扩展分区出现的原因是每个存储设备上只能有4个分区。可以通过创建多个扩展分区,然后在扩展分区内创建主分区进行扩展。②上例中创建了一个主分区,在存储设备上给它分配了分区号1,然后给它分配了2 GB的存储设备空间。你可以再次使用p命令查看结果。
Command (m for help): p Disk /dev/sdb: 5368 MB, 5368709120 bytes 255 heads, 63 sectors/track, 652 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk identifier: 0x029aa6af Device Boot Start End Blocks Id System /dev/sdb1 1 262 2104483+ 83 Linux Command (m for help): -
创建了想要的分区之后,用
w命令将更改保存到存储设备上。Command (m for help): w The partition table has been altered! Calling ioctl() to re-read partition table. Syncing disks. $存储设备的分区信息被写入分区表中,Linux系统通过ioctl()调用来获知新分区的出现。设置好分区之后,可以使用Linux文件系统对其进行格式化。
8.2.2 创建文件系统
在将数据存储到分区之前,你必须用某种文件系统对其进行格式化,这样Linux才能使用它。
每种文件系统类型都用自己的命令行程序来格式化分区。
并非所有文件系统工具都已经默认安装了。要想知道某个文件系统工具是否可用,可以使用type命令。
$ type mkfs.ext4
mkfs.ext4 is /sbin/mkfs.ext4
$
$ type mkfs.btrfs
-bash: type: mkfs.btrfs: not found
$
每个文件系统命令都有很多命令行选项,允许你定制如何在分区上创建文件系统。要查看所有可用的命令行选项,可用man命令来显示该文件系统命令的手册页面(参见第3章)。所有的文件系统命令都允许通过不带选项的简单命令来创建一个默认的文件系统。
$ sudo mkfs.ext4 /dev/sdb1
[sudo] password for Christine:
mke2fs 1.41.12 (17-May-2010)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
131648 inodes, 526120 blocks
26306 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=541065216
17 block groups
32768 blocks per group, 32768 fragments per group
7744 inodes per group
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912
Writing inode tables: done
Creating journal (16384 blocks): done
Writing superblocks and filesystem accounting information: done
This filesystem will be automatically checked every 23 mounts or
180 days, whichever comes first. Use tune2fs -c or -i to override.
$
为分区创建了文件系统之后,下一步是将它挂载到虚拟目录下的某个挂载点,这样就可以将数据存储在新文件系统中了。你可以将新文件系统挂载到虚拟目录中需要额外空间的任何位置。
$ ls /mnt
$
$ sudo mkdir /mnt/my_partition
$
$ ls -al /mnt/my_partition/
$
$ ls -dF /mnt/my_partition
/mnt/my_partition/
$
$ sudo mount -t ext4 /dev/sdb1 /mnt/my_partition
$
$ ls -al /mnt/my_partition/
total 24
drwxr-xr-x. 3 root root 4096 Jun 11 09:53 .
drwxr-xr-x. 3 root root 4096 Jun 11 09:58 ..
drwx------. 2 root root 16384 Jun 11 09:53 lost+found
$
mkdir命令(参见第3章)在虚拟目录中创建了挂载点,mount命令将新的硬盘分区添加到挂载点。mount命令的-t选项指明了要挂载的文件系统类型(ext4)。现在你可以在新分区中保存新文件和目录了!
这种挂载文件系统的方法只能临时挂载文件系统。当重启Linux系统时,文件系统并不会自动挂载。要强制Linux在启动时自动挂载新的文件系统,可以将其添加到/etc/fstab文件。
8.2.3 文件系统的检查与修复
就算是现代文件系统,碰上突然断电或者某个不规矩的程序在访问文件时锁定了系统,也会出现错误。幸而有一些命令行工具可以帮你将文件系统恢复正常。
每个文件系统都有各自可以和文件系统交互的恢复命令。好在有个通用的前端程序,可以决定存储设备上的文件系统并根据要恢复的文件系统调用适合的文件系统恢复命令。
fsck命令能够检查和修复大部分类型的Linux文件系统,包括本章早些时候讨论过的ext、
ext2、ext3、ext4、ReiserFS、JFS和XFS。该命令的格式是:fsck options filesystem
fsck命令使用/etc/fstab文件来自动决定正常挂载到系统上的存储设备的文件系统。如果存储设备尚未挂载(比如你刚刚在新的存储设备上创建了个文件系统),你需要用-t命令行选项来指定文件系统类型。表8-4列出了其他可用的命令行选项。
8.3 逻辑卷管理
如果用标准分区在硬盘上创建了文件系统,为已有文件系统添加额外的空间多少是一种痛苦
的体验。你只能在同一个物理硬盘的可用空间范围内调整分区大小。如果硬盘上没有地方了,你
就必须弄一个更大的硬盘,然后手动将已有的文件系统移动到新的硬盘上。
这时候可以通过将另外一个硬盘上的分区加入已有文件系统,动态地添加存储空间。Linux
逻辑卷管理器(logical volume manager,LVM)软件包正好可以用来做这个。它可以让你在无需
重建整个文件系统的情况下,轻松地管理磁盘空间。
8.3.1 逻辑卷管理布局
逻辑卷管理的核心在于如何处理安装在系统上的硬盘分区。在逻辑卷管理的世界里,硬盘称作物理卷(physical volume,PV)。每个物理卷都会映射到硬盘上特定的物理分区。
多个物理卷集中在一起可以形成一个卷组(volume group,VG)。逻辑卷管理系统将卷组视为一个物理硬盘,但事实上卷组可能是由分布在多个物理硬盘上的多个物理分区组成的。卷组提供了一个创建逻辑分区的平台,而这些逻辑分区则包含了文件系统。
整个结构中的最后一层是逻辑卷(logical volume,LV)。逻辑卷为Linux提供了创建文件系统的分区环境,作用类似于到目前为止我们一直在探讨的Linux中的物理硬盘分区。Linux系统将逻辑卷视为物理分区。
可以使用任意一种标准Linux文件系统来格式化逻辑卷,然后再将它加入Linux虚拟目录中的某个挂载点。
卷组横跨了三个不同的物理硬盘,覆盖了五个独立的物理分区。在卷组内部有两个独立的逻辑卷。Linux系统将每个逻辑卷视为一个物理分区。每个逻辑卷可以被格式化成ext4文件系统,然后挂载到虚拟目录中某个特定位置。第三个物理硬盘有一个未使用的分区。通过逻辑卷管理,你随后可以轻松地将这个未使用分区分配到已有卷组:要么用它创建一个新的逻辑卷,要么在需要更多空间时用它来扩展已有的逻辑卷。
8.3.2 Linux中的LVM
Linux LVM是由Heinz Mauelshagen开发的,于1998年发布到了Linux社区。它允许你在Linux上用简单的命令行命令管理一个完整的逻辑卷管理环境。
Linux LVM有两个可用的版本。
- LVM1:最初的LVM包于1998年发布,只能用于Linux内核2.4版本。它仅提供了基本的逻辑卷管理功能。
- LVM2:LVM的更新版本,可用于Linux内核2.6版本。它在标准的LVM1功能外提供了额外的功能。
-
快照
最初的Linux LVM允许你在逻辑卷在线的状态下将其复制到另一个设备。这个功能叫作快 照。在备份由于高可靠性需求而无法锁定的重要数据时,快照功能非常给力。传统的备份方法在将文件复制到备份媒体上时通常要将文件锁定。快照允许你在复制的同时,保证运行关键任务的Web服务器或数据库服务器继续工作。遗憾的是,LVM1只允许你创建只读快照。一旦创建了快照,就不能再写入东西了。
LVM2允许你创建在线逻辑卷的可读写快照。有了可读写的快照,就可以删除原先的逻辑卷,然后将快照作为替代挂载上。这个功能对快速故障转移或涉及修改数据的程序试验(如果失败,需要恢复修改过的数据)非常有用。
-
条带化
LVM2提供的另一个引人注目的功能是条带化(striping)。有了条带化,可跨多个物理硬盘创建逻辑卷。当Linux LVM将文件写入逻辑卷时,文件中的数据块会被分散到多个硬盘上。每个后继数据块会被写到下一个硬盘上。
条带化有助于提高硬盘的性能,因为Linux可以将一个文件的多个数据块同时写入多个硬盘,而无需等待单个硬盘移动读写磁头到多个不同位置。这个改进同样适用于读取顺序访问的文件,因为LVM可同时从多个硬盘读取数据。
LVM条带化不同于RAID条带化。LVM条带化不提供用来创建容错环境的校验信息。事实上,LVM条带化会增加文件因硬盘故障而丢失的概率。单个硬盘故障可能会造成多个逻辑卷无法访问。
-
镜像
通过LVM安装文件系统并不意味着文件系统就不会再出问题。和物理分区一样,LVM逻辑卷也容易受到断电和磁盘故障的影响。一旦文件系统损坏,就有可能再也无法恢复。
LVM快照功能提供了一些安慰,你可以随时创建逻辑卷的备份副本,但对有些环境来说可能还不够。对于涉及大量数据变动的系统,比如数据库服务器,自上次快照之后可能要存储成百上千条记录。
这个问题的一个解决办法就是LVM镜像。镜像是一个实时更新的逻辑卷的完整副本。当你创建镜像逻辑卷时,LVM会将原始逻辑卷同步到镜像副本中。根据原始逻辑卷的大小,这可能需要一些时间才能成。
一旦原始同步完成,LVM会为文件系统的每次写操作执行两次写入——一次写入到主逻辑卷,一次写入到镜像副本。可以想到,这个过程会降低系统的写入性能。就算原始逻辑卷因为某些原因损坏了,你手头也已经有了一个完整的最新副本!
8.3.3 使用Linux的LVM
-
定义物理卷
创建过程的第一步就是将硬盘上的物理分区转换成Linux LVM使用的物理卷区段。
我们的朋友
fdisk命令可以帮忙。在创建了基本的Linux分区之后,你需要通过t命令改变分区类型。[...] Command (m for help): t Selected partition 1 Hex code (type L to list codes): 8e Changed system type of partition 1 to 8e (Linux LVM) Command (m for help): p Disk /dev/sdb: 5368 MB, 5368709120 bytes 255 heads, 63 sectors/track, 652 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk identifier: 0xa8661341 Device Boot Start End Blocks Id System /dev/sdb1 1 262 2104483+ 8e Linux LVM Command (m for help): w The partition table has been altered! Calling ioctl() to re-read partition table. Syncing disks. $分区类型8e表示这个分区将会被用作Linux LVM系统的一部分,而不是一个直接的文件系统(就像你在前面看到的83类型的分区)
下一步是用分区来创建实际的物理卷。这可以通过
pvcreate命令来完成。pvcreate定义了用于物理卷的物理分区。它只是简单地将分区标记成Linux LVM系统中的分区而已。$ sudo pvcreate /dev/sdb1 dev_is_mpath: failed to get device for 8:17 Physical volume "/dev/sdb1" successfully created $如果你想查看创建进度的话,可以使用
pvdisplay命令来显示已创建的物理卷列表。$ sudo pvdisplay /dev/sdb1 "/dev/sdb1" is a new physical volume of "2.01 GiB" --- NEW Physical volume --- PV Name /dev/sdb1 VG Name PV Size 2.01 GiB Allocatable NO PE Size 0 Total PE 0 Free PE 0 Allocated PE 0 PV UUID 0FIuq2-LBod-IOWt-8VeN-tglm-Q2ik-rGU2w7 $pvdisplay命令显示出/dev/sdb1现在已经被标记为物理卷。注意,输出中的VG Name内容为空,因为物理卷还不属于某个卷组。
-
创建卷组
下一步是从物理卷中创建一个或多个卷组。究竟要为系统创建多少卷组并没有既定的规则,你可以将所有的可用物理卷加到一个卷组,也可以结合不同的物理卷创建多个卷组。
要从命令行创建卷组,需要使用
vgcreate命令。vgcreate命令需要一些命令行参数来定义卷组名以及你用来创建卷组的物理卷名。$ sudo vgcreate Vol1 /dev/sdb1 Volume group "Vol1" successfully created $输出结果平淡无奇。如果你想看看新创建的卷组的细节,可用
vgdisplay命令。$ sudo vgdisplay Vol1 --- Volume group --- VG Name Vol1 System ID Format lvm2 Metadata Areas 1 Metadata Sequence No 1 VG Access read/write VG Status resizable MAX LV 0 Cur LV 0 Open LV 0 Max PV 0 Cur PV 1 Act PV 1 VG Size 2.00 GiB PE Size 4.00 MiB Total PE 513 Alloc PE / Size 0 / 0 Free PE / Size 513 / 2.00 GiB VG UUID oe4I7e-5RA9-G9ti-ANoI-QKLz-qkX4-58Wj6e这个例子使用/dev/sdb1分区上创建的物理卷,创建了一个名为Vol1的卷组。
创建一个或多个卷组后,就可以创建逻辑卷了。
-
创建逻辑卷
Linux系统使用逻辑卷来模拟物理分区,并在其中保存文件系统。Linux系统会像处理物理分区一样处理逻辑卷,允许你定义逻辑卷中的文件系统,然后将文件系统挂载到虚拟目录上。
要创建逻辑卷,使用
lvcreate命令。虽然你通常不需要在其他Linux LVM命令中使用命令行选项,但lvcreate命令要求至少输入一些选项。$ sudo lvcreate -l 100%FREE -n lvtest Vol1 Logical volume "lvtest" created $-
查看创建的逻辑卷的详细情况:
lvdisplay$ sudo lvdisplay Vol1 --- Logical volume --- LV Path /dev/Vol1/lvtest LV Name lvtest VG Name Vol1 LV UUID 4W2369-pLXy-jWmb-lIFN-SMNX-xZnN-3KN208 LV Write Access read/write LV Creation host, time ... -0400 LV Status available
-
-
创建文件系统
运行完lvcreate命令之后,逻辑卷就已经产生了,但它还没有文件系统。你必须使用相应的命令行程序来创建所需要的文件系统。
$ sudo mkfs.ext4 /dev/Vol1/lvtest mke2fs 1.41.12 (17-May-2010) Filesystem label= OS type: Linux Block size=4096 (log=2) Fragment size=4096 (log=2) Stride=0 blocks, Stripe width=0 blocks 131376 inodes, 525312 blocks 26265 blocks (5.00%) reserved for the super user First data block=0 Maximum filesystem blocks=541065216 17 block groups 32768 blocks per group, 32768 fragments per group 7728 inodes per group Superblock backups stored on blocks: 32768, 98304, 163840, 229376, 294912 Writing inode tables: done Creating journal (16384 blocks): done Writing superblocks and filesystem accounting information: done This filesystem will be automatically checked every 28 mounts or 180 days, whichever comes first.Use tune2fs -c or -i to override. $在创建了新的文件系统之后,可以用标准Linux mount命令将这个卷挂载到虚拟目录中,就跟它是物理分区一样。唯一的不同是你需要用特殊的路径来标识逻辑卷。
$ sudo mount /dev/Vol1/lvtest /mnt/my_partition $ $ mount /dev/mapper/vg_server01-lv_root on / type ext4 (rw) [...] /dev/mapper/Vol1-lvtest on /mnt/my_partition type ext4 (rw) $ $ cd /mnt/my_partition $ $ ls -al total 24 drwxr-xr-x. 3 root root 4096 Jun 12 10:22 . drwxr-xr-x. 3 root root 4096 Jun 11 09:58 .. drwx------. 2 root root 16384 Jun 12 10:22 lost+found $注意,mkfs.ext4和mount命令中用到的路径都有点奇怪。路径中使用了卷组名和逻辑卷名,
而不是物理分区路径。文件系统被挂载之后,就可以访问虚拟目录中的这块新区域了。
-
修改LVM
Linux LVM的好处在于能够动态修改文件系统,因此最好有工具能够让你实现这些操作。在Linux有一些工具允许你修改现有的逻辑卷管理配置。
第9章:安装软件程序
安装软件
使用Debian包
使用Red hat包
Linux开发人员已经通过把软件打包成更易于安装的预编译包,我们的生活因此舒坦了一些。但你多少还是得花点功夫安装软件包,尤其是准备从命令行下安装的时候。本章将介绍Linux上能见到的各种包管理系统(package management system,PMS),以及用来进行软件安装、管理和删除的命令行工具。
9.1 包管理基础
PMS利用一个数据库来记录各种相关内容:
- Linux系统上已安装了什么软件包;
- 每个包安装了什么文件;
- 每个已安装软件包的版本。
软件包通常会依赖其他的包,为了前者能够正常运行,被依赖的包必须提前安装在系统中。PMS工具将会检测这些依赖关系,并在安装需要的包之前先安装好所有额外的软件包。
Linux中广泛使用的两种主要的PMS基础工具是dpkg和rpm
基于Debian的发行版(如Ubuntu和Linux Mint)使用的是dpkg命令,这些发行版的PMS工具也是以该命令为基础的。dpkg会直接和Linux系统上的PMS交互,用来安装、管理和删除软件包。
基于Red Hat的发行版(如Fedora、openSUSE及Mandriva)使用的是rpm命令,该命令是其PMS的底层基础。类似于dpkg命令,rmp命令能够列出已安装包、安装新包和删除已有软件。
9.2 基于Debian系统
dpkg命令是基于Debian系PMS工具的核心。包含在这个PMS中的其他工具有:
- apt-get
- apt-cache
- aptitude
到目前为止,最常用的命令行工具是aptitude,这是有原因的。aptitude工具本质上是apt工具和dpkg的前端。dpkg是软件包管理系统工具,而aptitude则是完整的软件包管理系统。
命令行下使用aptitude命令有助于避免常见的软件安装问题,如软件依赖关系缺失、系统环境不稳定及其他一些不必要的麻烦。
9.2.1 用aptitude管理软件包
Linux系统管理员面对的一个常见任务是确定系统上已经安装了什么软件包。
shell下: aptitude进入界面
如果你已经知道了系统上的那些软件包,只想快速显示某个特定包的详细信息,就没必要到aptitude的交互式界面。可以在命令行下以单个命令的方式使用aptitude。
aptitude show package_name
$ aptitude show mysql-client
Package: mysql-client
State: not installed
Version: 5.5.38-0ubuntu0.14.04.1
Priority: optional
Section: database
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Architecture: all
Uncompressed Size: 129 k
Depends: mysql-client-5.5
Provided by: mysql-client-5.5
Description: MySQL database client (metapackage depending on the latest version)
This is an empty package that depends on the current "best" version of
mysql-client (currently mysql-client-5.5), as determined by the MySQL
maintainers. Install this package if in doubt about which MySQL version you
want, as this is the one considered to be in the best shape by the Maintainers.
Homepage: http://dev.mysql.com/
无法通过aptitude看到的一个细节是所有跟某个特定软件包相关的所有文件的列表。要得到这个列表,就必须用dpkg命令。
dpkg -L package_name
$
$ dpkg -L vim-common
/.
/usr
/usr/bin
/usr/bin/xxd
/usr/bin/helpztags
/usr/lib
/usr/lib/mime
/usr/lib/mime/packages
/usr/lib/mime/packages/vim-common
/usr/share
/usr/share/man
/usr/share/man/ru
/usr/share/man/ru/man1
/usr/share/man/ru/man1/vim.1.gz
/usr/share/man/ru/man1/vimdiff.1.gz
/usr/share/man/ru/man1/xxd.1.gz
/usr/share/man/it
/usr/share/man/it/man1
[...]
$
同样可以进行反向操作,查找某个特定文件属于哪个软件包。
dpkg --search absolute_file_name
9.2.2 用aptitude安装软件包
aptitude search package_name
search选项的妙处在于你无需在package_name周围加通配符。通配符会隐式添加。下面是用aptitude来查找wine软件包的例子
$ aptitude search wine
p gnome-wine-icon-theme - red variation of the GNOME- ...
v libkwineffects1-api -
p libkwineffects1a - library used by effects...
p q4wine - Qt4 GUI for wine (W.I.N.E)
p shiki-wine-theme - red variation of the Shiki- ...
p wine - Microsoft Windows Compatibility ...
p wine-dev - Microsoft Windows Compatibility ...
p wine-gecko - Microsoft Windows Compatibility ...
p wine1.0 - Microsoft Windows Compatibility ...
p wine1.0-dev - Microsoft Windows Compatibility ...
p wine1.0-gecko - Microsoft Windows Compatibility ...
p wine1.2 - Microsoft Windows Compatibility ...
p wine1.2-dbg - Microsoft Windows Compatibility ...
p wine1.2-dev - Microsoft Windows Compatibility ...
p wine1.2-gecko - Microsoft Windows Compatibility ...
p winefish - LaTeX Editor based on Bluefish
注意,在每个包名字之前都有一个p或i。如果看到一个i,说明这个包现在已经安装到了你的系统上了。如果看到一个p或v,说明这个包可用,但还没安装。我们在上面的列表中可以看到系统中尚未安装wine,但是在软件仓库中可以找到这个包。
aptitude install package_name
$ sudo aptitude install wine
The following NEW packages will be installed:
cabextract{a} esound-clients{a} esound-common{a} gnome-exe-thumbnailer
{a}
icoutils{a} imagemagick{a} libaudio2{a} libaudiofile0{a} libcdt4{a}
libesd0{a} libgraph4{a} libgvc5{a} libilmbase6{a} libmagickcore3-extra
{a}
libmpg123-0{a} libnetpbm10{a} libopenal1{a} libopenexr6{a}
libpathplan4{a} libxdot4{a} netpbm{a} ttf-mscorefonts-installer{a}
ttf-symbol-replacement{a} winbind{a} wine wine1.2{a} wine1.2-gecko{a}
0 packages upgraded, 27 newly installed, 0 to remove and 0 not upgraded.
Need to get 0B/27.6MB of archives. After unpacking 121MB will be used.
Do you want to continue? [Y/n/?] Y
Preconfiguring packages ...
[...]
All done, no errors.
All fonts downloaded and installed.
Updating fontconfig cache for /usr/share/fonts/truetype/msttcorefonts
Setting up winbind (2:3.5.4~dfsg-1ubuntu7) ...
* Starting the Winbind daemon winbind
[ OK ]
Setting up wine (1.2-0ubuntu5) ...
Setting up gnome-exe-thumbnailer (0.6-0ubuntu1) ...
Processing triggers for libc-bin ...
ldconfig deferred processing now taking place
aptitude自动解析了必要的包依赖关系,并安装了需要的额外的库和软件包。这是许多包管理系统都有的非常好的功能。
9.2.3 更新软件包
尽管aptitude可以帮忙解决安装软件时遇到的问题,但解决有依赖关系的多个包的更新会比较烦琐。要用软件仓库中的新版本妥善地更新系统上所有的软件包,可用safe-upgrade选项。
aptitude safe-upgrade
注意,这个命令不需要使用软件包名称作为参数。因为safe-upgrade选项会将所有已安装的包更新到软件仓库中的最新版本,更有利于系统稳定。
显然,应该定期运行aptitude的safe-upgrade选项来保持系统处于最新状态。这点在
安装了一个全新的发行版之后尤其重要。通常在发行版推出最新的完整发布之后,就会
跟着出现很多新的安全补丁和更新。
9.2.4 卸载软件包
用aptitude卸载软件包与安装及更新它们一样容易。你要作出的唯一选择就是要不要保留软件数据和配置文件。
要想只删除软件包而不删除数据和配置文件,可以使用aptitude的remove选项。
要删除软件包和相关的数据和配置文件,可用purge选项。
要看软件包是否已删除,可以再用aptitude的search选项。如果在软件包名称的前面看到一个c,意味着软件已删除,但配置文件尚未从系统中清除;如果前面是个p的话,说明配置文件也已删除。
9.2.5 aptitude仓库
aptitude默认的软件仓库位置是在安装Linux发行版时设置的。具体位置存储在文件/etc/apt/sources. list中。
很多情况下,根本不需要添加或删除软件仓库,所以也没必要接触这个文件。但aptitude只会从这些仓库中下载文件。另外,在搜索软件进行安装或更新时,aptitude同样只会检查这些库。如果需要为你的PMS添加一些额外的软件仓库,就在这个文件中设置吧。
使用下面的结构来指定仓库源:deb (or deb-src) address *distribution_name package_type_list*
deb或deb-src的值表明了软件包的类型。deb值说明这是一个已编译程序源,而deb-src值则说明这是一个源代码的源。
address条目是软件仓库的Web地址。distribution_name条目是这个特定软件仓库的发行版版本的名称。
9.3 基于Red Hat的系统
和基于Debian的发行版类似,基于Red Hat的系统也有几种不同的可用前端工具。常见的有
以下3种:
- yum:在Red Hat和Fedora中使用
- urpm:在Mandriva中使用
- zypper:在openSUSE中使用
这些前端都是基于rpm命令行工具的。
9.3.1 列出已安装包
要找出系统上已安装的包,可在shell提示符下输入如下命令:
yum list installed
输出的信息可能会在屏幕上一闪而过,所以最好是将已安装包的列表重定向到一个文件中。可以用more或less命令(或一个GUI编辑器)按照需要查看这个列表。
yum list installed > installed_software
yum擅长找出某个特定软件包的详细信息。它能给出关于包的非常详尽的描述,另外你还可以通过一条简单的命令查看包是否已安装。
# yum list xterm
Loaded plugins: langpacks, presto, refresh-packagekit
Adding en_US to language list
Available Packages
xterm.i686 253-1.el6
#
# yum list installed xterm
Loaded plugins: refresh-packagekit
Error: No matching Packages to list
#
最后,如果需要找出系统上的某个特定文件属于哪个软件包,万能的yum可以做到!只要输入命令:
yum provides file_name
9.3.2 用yum安装软件
用yum安装软件包极其简单。下面这个简单的命令会从仓库中安装软件包、所有它需要的库以及依赖的其他包:yum install package_name
也可以手动下载rpm安装文件并用yum安装,这叫作本地安装。基本的命令是:
yum localinstall package_name.rpm
9.3.3 yum更新软件
要列出所有已安装包的可用更新,输入如下命令:yum list updates
如果想对更新列表中的所有包进行更新,只要输入如下命令:yum update
9.3.4 卸载软件
yum工具还提供了一种简单的方法来卸载系统中不再想要的应用。和aptitude一样,你需要决定是否保留软件包的数据和配置文件。
-
remove 删除软件保留配置文件
yum remove package_name -
erase 删除软件和所有文件
yum erase package_name
9.3.5 处理损坏的包依赖关系
有时在安装多个软件包时,某个包的软件依赖关系可能会被另一个包的安装覆盖掉。这叫作损坏的包依赖关系(broken dependency)。
如果系统出现了这个问题,先试试下面的命令:yum clean all
然后试着用yum命令的update选项。有时,只要清理了放错位置的文件就可以了。
如果这还解决不了问题,试试下面的命令:yum deplist xterm
这个命令显示了所有包的库依赖关系以及什么软件可以提供这些库依赖关系。一旦知道某个包需要的库,你就能安装它们了。
# yum deplist xterm
Loaded plugins: fastestmirror, refresh-packagekit, security
Loading mirror speeds from cached hostfile
* base: mirrors.bluehost.com
* extras: mirror.5ninesolutions.com
* updates: mirror.san.fastserv.com
Finding dependencies:
package: xterm.i686 253-1.el6
dependency: libncurses.so.5
provider: ncurses-libs.i686 5.7-3.20090208.el6
dependency: libfontconfig.so.1
provider: fontconfig.i686 2.8.0-3.el6
dependency: libXft.so.2
provider: libXft.i686 2.3.1-2.el6
dependency: libXt.so.6
provider: libXt.i686 1.1.3-1.el6
dependency: libX11.so.6
provider: libX11.i686 1.5.0-4.el6
dependency: rtld(GNU_HASH)
provider: glibc.i686 2.12-1.132.el6
provider: glibc.i686 2.12-1.132.el6_5.1
provider: glibc.i686 2.12-1.132.el6_5.2
dependency: libICE.so.6
provider: libICE.i686 1.0.6-1.el6
dependency: libXaw.so.7
provider: libXaw.i686 1.0.11-2.el6
dependency: libtinfo.so.5
provider: ncurses-libs.i686 5.7-3.20090208.el6
dependency: libutempter.so.0
provider: libutempter.i686 1.1.5-4.1.el6
dependency: /bin/sh
provider: bash.i686 4.1.2-15.el6_4
dependency: libc.so.6(GLIBC_2.4)
provider: glibc.i686 2.12-1.132.el6
provider: glibc.i686 2.12-1.132.el6_5.1
provider: glibc.i686 2.12-1.132.el6_5.2
dependency: libXmu.so.6
provider: libXmu.i686 1.1.1-2.el6
如果还没有解决问题,还有最后一招:
yum update --skip-broken
--skip-broken选项允许你忽略依赖关系损坏的那个包,继续去更新其他软件包。这可能救不了损坏的包,但至少可以更新系统上的其他包。
9.3.6 yum软件仓库
类似于aptitude系统,yum也是在安装发行版的时候设置的软件仓库。这些预设的仓库就能很好地满足你的大部分需求。
要想知道你现在正从哪些仓库中获取软件,输入如下命令:yum repolist
如果仓库中没有需要的软件,你可以编辑一下配置文件。yum的仓库定义文件位于/etc/yum.repos.d。你需要添加正确的URL,并获得必要的加密密钥。
像rpmfusion.org这种优秀的仓库站点会列出必要的使用步骤。有时这些仓库网站会提供一个可下载的rpm文件,可以用yum localinstall命令进行安装。这个rpm文件在安装过程会为你完成所有的仓库设置工作。现在方便多了!
9.4 从源码安装
如果你经常在开源软件环境中工作,就很可能会遇到打包成tarball形式的软件。
将文件下载到你的Linux系统上,然后解包。要解包一个软件的tarball,用标准的tar命令。
#
# tar -zxvf sysstat-11.1.1.tar.gz
sysstat-11.1.1/
sysstat-11.1.1/cifsiostat.c
sysstat-11.1.1/FAQ
sysstat-11.1.1/ioconf.h
sysstat-11.1.1/rd_stats.h
sysstat-11.1.1/COPYING
sysstat-11.1.1/common.h
sysstat-11.1.1/sysconfig.in
sysstat-11.1.1/mpstat.h
sysstat-11.1.1/rndr_stats.h
[...]
sysstat-11.1.1/activity.c
sysstat-11.1.1/sar.c
sysstat-11.1.1/iostat.c
sysstat-11.1.1/rd_sensors.c
sysstat-11.1.1/prealloc.in
sysstat-11.1.1/sa2.in
#
#
在这个目录的列表中,应该能看到README或AAAREADME文件。读这个文件非常重要。该文件中包含了软件安装所需要的操作。
按照README文件中的建议,下一步是为系统配置sysstat。它会检查你的Linux系统,确保它拥有合适的编译器能够编译源代码,另外还要具备正确的库依赖关系。
# ./configure
如果哪里有错了,在configure步骤中会显示一条错误消息说明缺失了什么东西。如果你所用的Linux发行版中没有安装GNU C编译器,那只会得到一条错误信息。对于其他问题,你会看到好几条消息,说明安装了什么,没有安装什么。
下一步就是用make命令来构建各种二进制文件。make命令会编译源码,然后链接器会为这个包创建最终的可执行文件。和configure命令一样,make命令会在编译和链接所有的源码文件的过程中产生大量的输出。
make
make步骤结束时,可运行的sysstat软件程序就会出现在目录下!但是从那个目录下运行程序有些不便。你会想将它安装到Linux系统中常用的位置上。要这样的话,就必须以root用户身份登录(或者用sudo命令,如果你的Linux发行版偏好这个的话),然后用make命令的install选项。
make install
第10章:使用编辑器
vim 编辑器
nano编辑器
emacs编辑器
KWrite编辑器
Kate编辑器
GNOME编辑器
10.1 vim 编辑器
vi编辑器是Unix系统最初的编辑器。它使用控制台图形模式来模拟文本编辑窗口,允许查看文件中的行、在文件中移动、插入、编辑和替换文本。
尽管它可能是世界上最复杂的编辑器(至少讨厌它的人是这么认为的),但其拥有的大量特性使其成为Unix管理员多年来的支柱性工具。
在GNU项目将vi编辑器移植到开源世界时,他们决定对其作一些改进。由于它不再是以前Unix中的那个原始的vi编辑器了,开发人员也就将它重命名为vi improved,或vim。
10.1.1 检查vim软件包
在开始研究vim编辑器之前,最好先搞明白你所用的Linux系统是哪种vim软件包。在有些发行版中安装的是完整的vim,另外还有一个vi命令的别名,就像下面所显示的CentOS发行版中的那样。
在Ubuntu发行版中安装基础版的vim包非常简单:
$ sudo apt-get install vim
基础版的vim现在安装好了,/usr/bin/vi的文件链接会自动更改成指向/usr/bin/ vim.basic。以后再输入vi命令的时候,使用的就是基础版的vim编辑器了。
10.1.2 vim基础
vim编辑器在内存缓冲区中处理数据。只要键入vim命令(或vi,如果这个别名或链接文件存在的话)和要编辑的文件的名字就可以启动vim编辑器:
vim myprog.c
如在启动vim时未指定文件名,或者这个文件不存在,vim会开辟一段新的缓冲区域来编辑。如果你在命令行下指定了一个已有文件的名字,vim会将文件的整个内容都读到一块缓冲区域来准备编辑
vim编辑器会检测会话终端的类型(参见第2章),并用全屏模式将整个控制台窗口作为编辑器区域。
最初的vim编辑窗口显示了文件的内容(如果有内容的话),并在窗口的底部显示了一条消息行。如果文件内容并未占据整个屏幕,vim会在非文件内容行放置一个波浪线(如图10-1所示)。
底部的消息行根据文件的状态以及vim安装时的默认设置显示了所编辑文件的信息。如果文件是新建的,会出现消息[New File]。
vim两种操作模式:
- 普通模式
- 插入模式
当你刚打开要编辑的文件时(或新建一个文件时),vim编辑器会进入普通模式。在普通模式中,vim编辑器会将按键解释成命令)。
在插入模式下,vim会将你在当前光标位置输入的每个键都插入到缓冲区。按下i键就可以进入插入模式。要退出插入模式回到普通模式,按下键盘上的退出键(ESC键,也就是Escape键)就可以了。
在普通模式中,可以用方向键在文本区域移动光标(只要vim能正确识别你的终端类型)。如果你恰巧在一个古怪的没有定义方向键的终端连接上,也不是完全没有希望。vim中有用来移动光标的命令。
-
h:左移一个字符。
-
j:下移一行(文本中的下一行)。
-
k:上移一行(文本中的上一行)。
-
l:右移一个字符。
在大的文本文件中一行一行地来回移动会特别麻烦,幸而vim提供了一些能够提高移动速度的命令。
-
PageDown(或Ctrl+F):下翻一屏。
-
PageUp(或Ctrl+B):上翻一屏。
-
G:移到缓冲区的最后一行。
-
num G:移动到缓冲区中的第num行。
-
gg:移到缓冲区的第一行。
vim编辑器在普通模式下有个特别的功能叫命令行模式。命令行模式提供了一个交互式命令行,可以输入额外的命令来控制vim的行为。要进入命令行模式,在普通模式下按下冒号键。光标会移动到消息行,然后出现冒号,等待输入命令
在命令行模式下有几个命令可以将缓冲区的数据保存到文件中并退出vim:
-
q:如果未修改缓冲区数据,退出。
-
q!:取消所有对缓冲区数据的修改并退出。
-
w filename:将文件保存到另一个文件中。
-
wq:将缓冲区数据保存到文件中并退出。
10.1.3 编辑数据
在插入模式下,你可以向缓冲区插入数据。然而有时将数据输入到缓冲区中后,你需要再对其进行添加或删除。在普通模式下,vim编辑器提供了一些命令来编辑缓冲区中的数据。
有些编辑命令允许使用数字修饰符来指定重复该命令多少次。比如,命令2x会删除从光标当前位置开始的两个字符,命令5dd会删除从光标当前所在行开始的5行。
在vim编辑器的普通模式下使用退格键(Backspace键)和删除键(Delete键)时要留心。
vim编辑器通常会将删除键识别成x命令的功能,删除当前光标所在位置的字符。vim编辑
器在普通模式下通常不识别退格键。
10.1.4 复制和粘贴
现代编辑器的标准功能之一是剪切或复制数据,然后粘贴在文本的其他地方。vim编辑器也可以这么做。
剪切和粘贴相对容易一些。但vim在删除数据时,实际上会将数据保存在单独的一个寄存器中。可以用p命令取回数据。
举例来说,可以用dd命令删除一行文本,然后把光标移动到缓冲区的某个要放置该行文本的位置,然后用p命令。该命令会将文本插入到当前光标所在行之后。可以将它和任何删除文本的命令一起搭配使用。
复制文本则要稍微复杂点。vim中复制命令是y(代表yank)。可以在y后面使用和d命令相同的第二字符(yw表示复制一个单词,y$表示复制到行尾)。在复制文本后,把光标移动到你想放置文本的地方,输入p命令。复制的文本就会出现在该位置。
可视模式会在你移动光标时高亮显示文本。可以用可视模式选取要复制的文本。要进入可视模式,应移动光标到要开始复制的位置,并按下v键。你会注意到光标所在位置的文本已经被高亮显示了。下一步,移动光标来覆盖你想要复制的文本(甚至可以向下移动几行来复制更多行的文本)。在移动光标时,vim会高亮显示复制区域的文本。在覆盖了要复制的文本后,按y键来激活复制命令。现在寄存器中已经有了要复制的文本,移动光标到你要放置的位置,使用p命令来粘贴。
10.1.5 查找和替换
可以使用vim查找命令来轻松查找缓冲区中的数据。要输入一个查找字符串,就按下斜线(/)键。光标会跑到消息行,然后vim会显示出斜线。在输入你要查找的文本后,按下回车键。vim编辑器会采用以下三种回应中的一种:
-
如果要查找的文本出现在光标当前位置之后,则光标会跳到该文本出现的第一个位置。
-
如果要查找的文本未在光标当前位置之后出现,则光标会绕过文件末尾,出现在该文本所在的第一个位置(并用一条消息指明)。
-
输出一条错误消息,说明在文件中没有找到要查找的文本。
要继续查找同一个单词,按下斜线键,然后按回车键。或者使用n键,表示下一个(next)。
替换命令允许你快速用另一个单词来替换文本中的某个单词。必须进入命令行模式才能使用替换命令。替换命令的格式是::s/old/new/
vim编辑器会跳到old第一次出现的地方,并用new来替换。可以对替换命令作一些修改来替换多处文本。
-
😒/old/new/g:一行命令替换所有old。
-
:n,ms/old/new/g:替换行号n和m之间所有old。
-
:%s/old/new/g:替换整个文件中的所有old。
-
:%s/old/new/gc:替换整个文件中的所有old,但在每次出现时提示。

浙公网安备 33010602011771号