Notes#9077: 快乐的Linux命令行

http://billie66.github.io/TLCL/

Ch1: 引言

Ch2: 什么是Shell

2.5 关于鼠标和光标

X窗口系统(使GUI工作的底层引擎)内建了一种机制,支持快速拷贝和粘贴技巧。如果你想高亮一些文本,可以按下鼠标左键,沿着文本拖动鼠标(或者双击一个单词),那么这些高亮的文本就被拷贝到了一个由X管理的缓冲区里面。然后按下鼠标中键,这些文本就被粘贴到光标所在的位置。

设置聚焦策略为“聚焦跟随着鼠标”,可以使拷贝和粘贴技巧更有益。在窗口管理器的配置程序中,你会找到这个设置。

2.6 试试运行一些简单命令

2.8 幕后控制台

在大多数Linux发行版中,按下Ctrl-Alt-F1到Ctrl-Alt-F6访问不同的虚拟终端。当一个会话被访问的时候,它会显示登录提示框,我们需要输入用户名和密码。从一个虚拟控制台转换到另一个,按下Alt和F1-F6中的一个。返回图形桌面,按下 Alt-F7。

Ch3: 文件系统中跳转

3.2 当前工作目录

我们使用pwd (print working directory) 命令,来显示当前工作目录。

3.7 有用的快捷键

用ls -a 命令列出隐藏文件。

Ch4: 探究操作系统

4.4 确定文件类型

$ file filename 调用file命令。

4.5 用less浏览文件内容

许多包含系统设置的文件(叫做配置文件),是以文本格式存储的,阅读它们可以更深入的了解系统是如何工作的。

$ less filename

less程序最常用的键盘命令

命令 行为
Page Up or b 向上翻滚一页
Page Down or space 向下翻滚一页
Up Arrow 向上翻滚一行
Down Arrow 向下翻滚一行
G 移动到最后一行
1G or g 移动到开头一行
/characters 向前查找指定的字符串
n 向前查找下一个出现的字符串,这个字符串是之前所指定查找的
h 显示帮助屏幕
q 退出less程序

4.7 旅行指南

Linux系统目录介绍

目录 评论
/ 根目录,万物起源。
/bin 包含系统启动和运行所必须的二进制程序。
/boot 包含Linux内核,最初的RMA磁盘映像(系统启动时,由驱动程序所需),和启动加载程序。
有趣的文件:
  • /boot/grub/grub.conf or menu.lst,被用来配置启动加载程序。
  • /boot/vmlinuz,Linux内核。
/dev 这是一个包含设备结点的特殊目录。“一切都是文件”,也适用于设备。在这个目录里,内核维护着它支持的设备。
/etc 这个目录包含所有系统层面的配置文件。它也包含一系列的shell脚本,在系统启动时,这些脚本会运行每个系统服务。这个目录中的任何文件应该是可读的文本文件。
有意思的文件:
虽然/etc目录中的任何文件都有趣,但这里只列出了一些我一直喜欢的文件:
  • /etc/crontab,定义自动运行的任务。
  • /etc/fstab,包含存储设备的列表,以及与他们相关的挂载点。
  • /etc/passwd,包含用户帐号列表。
/home 在通常的配置环境下,系统会在/home下,给每个用户分配一个目录。普通用户只能在他们自己的目录下创建文件。这个限制保护系统免受错误的用户活动破坏。
/lib 包含核心系统程序所需的库文件。这些文件与Windows中的动态链接库相似。
/lost+found 每个使用Linux文件系统的格式化分区或设备,例如ext3文件系统,都会有这个目录。当部分恢复一个损坏的文件系统时,会用到这个目录。除非文件系统真正的损坏了,那么这个目录会是个空目录。
/media 在现在的Linux系统中,/media目录会包含可移除媒体设备的挂载点,例如USB驱动器,CDROMs等等。这些设备连接到计算机之后, 会自动地挂载到这个目录结点下。
/mnt 在早些的Linux系统中,/mnt目录包含可移除设备的挂载点。
/opt 这个/opt目录被用来安装“可选的”软件。这个主要用来存储可能安装在系统中的商业软件产品。
/proc 这个/proc目录很特殊。从存储在硬盘上的文件的意义上说,它不是真正的文件系统。反而,它是一个由Linux内核维护的虚拟文件系统。它所包含的文件是内核的窥视孔。这些文件是可读的,它们会告诉你内核是怎样监管计算机的。
/root root帐户的主目录。
/sbin 这个目录包含“系统”二进制文件。它们是完成重大系统任务的程序,通常为超级用户保留。
/tmp 这个/tmp目录,是用来存储由各种程序创建的临时文件的地方。一些配置,导致系统每次重新启动时,都会清空这个目录。
/usr 在Linux系统中,/usr目录可能是最大的一个。它包含普通用户所需要的所有程序和文件。
/usr/bin /usr/bin目录包含系统安装的可执行程序。通常,这个目录会包含许多程序。
/usr/lib 包含由/usr/bin目录中的程序所用的共享库。
/usr/local 这个/usr/local目录,是非系统发行版自带,却打算让系统使用的程序的安装目录。通常,由源码编译的程序会安装在/usr/local/bin目录下。新安装的Linux系统中,会存在这个目录,但却是空目录,直到系统管理员放些东西到它里面。
/usr/sbin 包含许多系统管理程序。
/usr/share /usr/share目录包含许多由/usr/bin目录中的程序使用的共享数据。其中包括像默认的配置文件,图标,桌面背景,音频文件等等。
/usr/share/doc 大多数安装在系统中的软件包会包含一些文档。在/usr/share/doc 目录下,我们可以找到按照软件包分类的文档。
/var 除了/tmp和/home目录之外,相对来说,目前我们看到的目录是静态的,这是说,它们的内容不会改变。/var目录是可能需要改动的文件存储的地方。各种数据库,假脱机文件,用户邮件等等,都驻扎在这里。
/var/log 这个/var/log目录包含日志文件,各种系统活动的记录。这些文件非常重要,并且应该时时监测它们。其中最重要的一个文件是/var/log/messages。注意,为了系统安全,在一些系统中,你必须是超级用户才能查看这些日志文件。

Ch5: 操作文件和目录

5.1 通配符

通配符列表

通配符 意义
* 匹配任意多个字符(包括零个或一个)
? 匹配任意一个字符(不包括零个)
[characters] 匹配任意一个属于字符集中的字符
[!characters] 匹配任意一个不是字符集中的字符
[[:class:]] 匹配任意一个属于指定字符类中的字符

普遍使用的字符类

字符类 意义
[:alnum:] 匹配任意一个字母或数字
[:alpha:] 匹配任意一个字母
[:digit:] 匹配任意一个数字
[:lower:] 匹配任意一个小写字母
[:upper] 匹配任意一个大写字母

通配符范例

模式 匹配对象
* 所有文件
g* 文件名以“g”开头的文件
b*.txt 以"b"开头,中间有零个或任意多个字符,并以".txt"结尾的文件
Data??? 以“Data”开头,其后紧接着3个字符的文件
[abc]* 文件名以"a","b",或"c"开头的文件
BACKUP.[0-9][0-9][0-9] 以"BACKUP."开头,并紧接着3个数字的文件
[[:upper:]]* 以大写字母开头的文件
[![:digit:]]* 不以数字开头的文件
*[[:lower:]123] 文件名以小写字母结尾,或以“1”,“2”,或“3”结尾的文件

5.2 mkdir 创建目录

5.3 cp 复制文件和目录

5.5 mv 移动和重命名文件

5.7 rm 删除文件和目录

5.9 ln 创建链接

5.10 硬链接

硬链接是最初Unix创建链接的方式,而符号链接更加现代。在默认情况下,每个文件有一个硬链接,这个硬链接给文件起名字。当我们创建一个硬链接以后,就为文件创建了一个额外的目录条目。
硬链接有两个重要局限性:
1. 一个硬链接不能关联它所在文件系统之外的文件。这是说一个链接不能关联与链接本身不在同一个磁盘分区上的文件。
2. 一个硬链接不能关联一个目录。

一个硬链接和文件本身没有什么区别。不像符号链接,当你列出一个包含硬链接的目录内容时,你会看到没有特殊的链接指示说明。当一个硬链接被删除时,这个链接被删除,但是文件本身的内容仍然存在(这是说,它所占的磁盘空间不会被重新分配),直到所有关联这个文件的链接都删除掉。知道硬链接很重要,因为你可能有时会遇到它们,但现在实际中更喜欢使用符号链接。

5.11 符号链接

创建符号链接是为了克服硬链接的局限性。符号链接生效,是通过创建一个特殊类型的文件,这个文件包含一个关联文件或目录的文本指针。在这一方面,它们和 Windows 的快捷方式差不多,当然,符号链接早于Windows的快捷方式很多年;-)

一个符号链接指向一个文件,而且这个符号链接本身与其它的符号链接几乎没有区别。例如,如果你往一个符号链接里面写入东西,那么相关联的文件也被写入。然而,当你删除一个符号链接时,只有这个链接被删除,而不是文件自身。如果删除这个文件早于文件的符号链接,这个链接仍然存在,但是不指向任何东西。在这种情况下,这个链接被称为坏链接。在许多实现中,ls命令会以不同的颜色展示坏链接,比如说红色,来显示它们的存在。

5.15 创建硬链接

你要记得一个文件至少有一个硬链接,因为文件名就是由链接创建的。

ls命令有一种方法,来展示(文件索引节点)的信息。在命令中加上"-i"选项:
[me@linuxbox playground]$ ls -li
total 16
12353538 -rw-r--r-- 4 me me 1650 2008-01-10 16:33 fun
12353538 -rw-r--r-- 4 me me 1650 2008-01-10 16:33 fun-hard
在这个版本的列表中,第一字段表示文件索引节点号,正如我们所见到的,fun和fun-hard共享一样的索引节点号,这就证实这两个文件是一样的文件。

5.17 移动文件和目录

对于符号链接,有一点值得记住,执行的大多数文件操作是针对链接的对象,而不是链接本身。而rm命令是个特例。当你删除链接的时候, 删除链接本身,而不是链接的对象。

文件管理器GNOME和KDE都提供了一个简单而且自动化的方法来创建符号链接。在GNOME里面,当拖动文件时,同时按下Ctrl+Shift按键会创建一个链接,而不是复制(或移动)文件。

Ch6: 使用命令

6.1 到底什么是命令?

可以是下面四种形式之一:

6.3 type 显示命令的类型

$ type command

6.4 which 显示一个可执行程序的位置

6.8 man 显示程序手册页

在大多数Linux系统中,man使用less工具来显示参考手册,所以当浏览文档时,你所熟悉的less命令都能有效。

man 所显示的手册页的布局

章节 内容
1 用户命令
2 程序接口内核系统调用
3 C 库函数程序接口
4 特殊文件,比如说设备结点和驱动程序
5 文件格式
6 游戏娱乐,如屏幕保护程序
7 其他方面
8 系统管理员命令

使用man命令来指定章节号:$ man section search_term
例如:$ man 5 passwd 会显示文件/etc/passwd的文件格式说明手册。

6.9 apropos 显示适当的命令

以“floppy”为关键词来搜索参考手册的例子:$ apropos floppy

man 命令加上“-k”选项,和apropos完成一样的功能。

6.10 whatis 显示非常简洁的命令说明

6.11 info 显示程序Info条目

info页是超级链接形式的,和网页很相似。

info程序读取info文件,info文件是树型结构,分化为各个结点,每一个包含一个题目。info文件包含超级链接,它可以让你从一个结点跳到另一个结点。一个超级链接可通过它开头的星号来辨别出来,把光标放在它上面并按下enter键,就可以激活它。

info 命令

命令 行为
? 显示命令帮助
PgUp or Backspace 显示上一页
PgDn or Space 显示下一页
n 下一个-显示下一个结点
p 上一个-显示上一个结点
u Up-显示当前所显示结点的父结点,通常是个菜单
Enter 激活光标位置下的超级链接
q 退出

到目前为止,我们所讨论的大多数命令行程序,属于GNU项目"coreutils"包,所以输入:
$ info coreutils
将会显示一个包含超级链接的手册页,这些超级链接指向包含在coreutils包中的各个程序。

6.12 README和其它程序文档

许多安装在你系统中的软件,都有自己的文档文件,这些文件位于/usr/share/doc目录下。这些文件大多数是以文本文件的形式存储的,可用less阅读器来浏览。一些文件是HTML格式,可用网页浏览器来阅读。我们可能遇到许多以".gz"结尾的文件。这表示gzip压缩程序已经压缩了这些程序。gzip 软件包包括一个特殊的less版本,叫做zless,zless 可以显示由gzip 压缩的文本文件的内容。

6.13 用别名(alias)创建你自己的命令

$ alias name='string'

删除别名,使用unalias命令。

Ch7: 重定向

7.2 重定向标准输出

举例:$ ls -l > ls-output.txt

一个删除文件内容或者创建一个新的空文件的技巧:$ >ls-output.txt
简单地使用重定向符,没有命令在它之前,这会删除一个已存在文件的内容或是创建一个新的空文件。这是因为,当我们使用">"重定向符来重定向输出结果时,目标文件总是从开头被重写。

用">>"重定向符可以把重定向结果追加到文件内容后面,而不是从开头重写文件。

7.3 重定向标准错误

重定向标准错误缺乏专用的重定向操作符。重定向标准错误,我们必须参考它的文件描述符。一个程序可以在几个编号的文件流中的任一个上产生输出。然而我们必须把这些文件流的前三个看作标准输入,输出和错误,shell内部参考它们为文件描述符0,1和2,各自地。shell提供了一种表示法来重定向文件,使用文件描述符。因为标准错误和文件描述符2一样,我们用这种表示法来重定向标准错误:
$ ls -l /bin/usr 2> ls-error.txt
文件描述符"2",紧挨着放在重定向操作符之前,来执行重定向标准错误到文件ls-error.txt任务。

7.4 重定向标准输出和错误到同一个文件

有两种方法来完成任务。

第一个,传统的方法,在旧版本shell中也有效:
$ ls -l /bin/usr > ls-output.txt 2>&1
使用这种方法,我们完成两个重定向。首先重定向标准输出到文件ls-output.txt,然后重定向文件描述符2(标准错误)到文件描述符1(标准输出)使用表示法2>&1。

注意重定向的顺序安排非常重要。标准错误的重定向必须总是出现在标准输出重定向之后,要不然它不起作用。上面的例子,
>ls-output.txt 2>&1
重定向标准错误到文件ls-output.txt,但是如果命令顺序改为:
2>&1 >ls-output.txt
则标准错误定向到屏幕。

现在的bash版本提供了第二种方法,更精简合理的方法来执行这种联合的重定向。
$ ls -l /bin/usr &> ls-output.txt
在这个例子里面,我们使用单单一个表示法 &> 来重定向标准输出和错误到文件ls-output.txt。

7.5 处理不需要的输出

重定向到/dev/null中去。举例:$ ls -l /bin/usr 2> /dev/null

7.7 cat 连接文件

cat 命令读取一个或多个文件,然后复制它们到标准输出。

cat经常被用来显示简短的文本文件。因为cat可以接受不只一个文件作为参数,所以它也可以用来把文件连接在一起。

比方说我们下载了一个大型文件,这个文件被分离成多个部分(USENET中的多媒体文件经常以这种方式分离),我们想把它们连起来。
我们能用这个命令把它们连接起来:
cat movie.mpeg.0* > movie.mpeg
因为通配符总是以有序的方式展开, 所以这些参数会以正确顺序安排。

如果我们输入不带参数的"cat"命令, 会发生什么呢:
[me@linuxbox ~]$ cat
没有发生任何事情,它只是坐在那里,好像挂掉了一样。看起来是那样,但是它正在做它该做的事情:如果cat没有给出任何参数,它会从标准输入读入数据,因为标准输入,默认情况下,连接到键盘。它正在等待我们输入数据!试试这个:
[me@linuxbox ~]$ cat
The quick brown fox jumped over the lazy dog.
下一步,输入 Ctrl-d(按住 Ctrl 键同时按下"d"),来告诉cat,在标准输入中,它已经到达文件末尾(EOF):由于文件名参数的缺席,cat复制标准输入到标准输出,所以我们看到文本行重复出现。
我们可以使用这种行为来创建简短的文本文件。比方说,我们想创建一个叫做"lazy_dog.txt"的文件,这个文件包含例子中的文本。我们这样做:
[me@linuxbox ~]$ cat > lazy_dog.txt
The quick brown fox jumped over the lazy dog.
输入命令,其后输入要放入文件中的文本。记住,最后输入 Ctrl-d。通过使用这个命令,我们实现了世界上最低能的文字处理器!
现在我们知道怎讲接受标准输入,除了文件名参数,让我们试着重定向标准输入:
[me@linuxbox ~]$ cat < lazy_dog.txt
The quick brown fox jumped over the lazy dog.
使用“<”重定向操作符,我们把标准输入源从键盘改到文件lazy_dog.txt,我们看到结果和传递单个文件名作为参数的执行结果一样。把这和传递一个文件名参数作比较,尤其没有意义,但它是用来说明把一个文件作为标准输入源。

7.8 管道线

7.9 过滤器

把目录/bin 和/usr/bin 中的可执行程序都联合在一起,再把它们排序,然后浏览执行结果:
$ ls /bin /usr/bin | sort | less

7.10 uniq 报道或忽略重复行

一个很实用的组合命令:
$ ls /bin /usr/bin | sort | uniq | less

如果我们想看到重复的数据列表,让uniq命令带上"-d"选项。

7.11 wc 打印行数,字数和字节数

例如:$ wc ls-output.txt
7902 64566 503634 ls-output.txt

"-l"选项限制命令输出只能报道行数。添加wc到管道线来统计数据,是个很便利的方法。查看我们的有序列表中程序个数,我们可以这样做:
$ ls /bin /usr/bin | sort | uniq | wc -l
2728

7.12 grep 打印匹配行

grep pattern [file...]

grep有两个很方便的选项:
"-i"导致 grep 忽略大小写当执行搜索时(通常,搜索是大小写敏感的);
"-v"选项会告诉grep只打印不匹配的行。

7.13 head/tail 打印文件开头部分/结尾部分

默认情况下,两个命令都打印十行文本,但是可以通过"-n"选项来调整命令打印的行数。
$ head -n 5 ls-output.txt
$ tail -n 5 ls-output.txt

tail有一个-f选项允许你实时的浏览文件。使用"-f"选项,tail命令继续监测这个文件,当新的内容添加到文件后,它们会立即出现在屏幕上。这会一直继续下去直到你输入Ctrl-c。[Bliss:这个功能测试失败。]

7.14 tee 从stdin读取数据,并同时输出到stdout和文件

tee程序从标准输入读入数据,并且同时复制数据到标准输出(允许数据继续随着管道线流动)和一个或多个文件。当在某个中间处理阶段来捕捉一个管道线的内容时,这很有帮助。

例如: $ ls /usr/bin | tee ls.txt | grep zip

Ch8: 从shell眼中看世界

8.1 (字符)展开

$ echo *
Desktop Documents ls-output.txt Music Pictures Public Templates Videos
为什么 echo 不打印"*"呢?在echo命令被执行前。当回车键被按下时,shell在命令被执行前在命令行上自动展开任何符合条件的字符,所以echo命令从不会发现"*",只把它展开成结果。

8.2 路径名展开

例如:

$ echo D*
Desktop Documents

$ echo *s
Documents Pictures Templates Videos

$ echo [[:upper:]]*
Desktop Documents Music Pictures Public Templates Videos

$ echo /usr/*/share
/usr/kerberos/share /usr/local/share

带有 -A 选项(almost all)的ls命令能够提供一份正确的隐藏文件清单。

8.3 波浪线展开

波浪线字符("~")有特殊的意思。当它用在一个单词的开头时,它会展开成指定用户的主目录名,如果没有指定用户名,则是当前用户的主目录。

$ echo ~
/home/me

如果有用户"foo"这个帐号,然后:
$ echo ~foo
/home/foo

8.4 算术表达式展开

$((expression))

算术表达式只支持整数(全部是数字,不带小数点)!

算术操作符

操作符 说明
+
-
*
/ 除(但是记住,因为展开只是支持整数除法,所以结果是整数。)
% 取余
** 取幂

在算术表达式中空格并不重要,并且表达式可以嵌套。例如,5的平方乘以3:
$ echo $(($((5**2))*3))
75
一对括号可以用来把多个子表达式括起来。通过这个技术,我们可以重写上面的例子,同时用一个展开代替两个,来得到一样的结果:
$ echo $(((5**2)*3))
75

8.5 花括号展开

花括号展开模式可能包含一个开头部分叫做报头,一个结尾部分叫做附言。花括号表达式本身可能包含一个由逗号分开的字符串列表,或者一系列整数,或者单个的字符串。这种模式可能不包括嵌入的空白。

这个例题使用了一系列整数:
$ echo Number_{1..5}
Number_1 Number_2 Number_3 Number_4 Number_5

一系列以倒序排列的字母花括号展开:
$ echo {Z..A}
Z Y X W V U T S R Q P O N M L K J I H G F E D C B A

花括号展开可以嵌套:
$ echo a{A{1,2},B{3,4}}b
aA1b aA2b aB3b aB4b

8.6 参数展开

$ echo $USER
me

查看有效的变量列表:
$ printenv | less

你可能注意到其它展开类型,如果你误输入一个模式,展开就不会发生。这时echo命令只简单地显示误键入的模式。通过参数展开,如果你拼写错了一个变量名,展开仍然会进行,只是展成一个空字符串:
$ echo $SUER
$

8.7 命令替换

命令替换允许我们把一个命令的输出作为一个展开模式来使用:
$ echo $(ls)
Desktop Documents ls-output.txt Music Pictures Public Templates Videos

$ ls -l $(which cp)
-rwxr-xr-x 1 root root 71516 2007-12-05 08:58 /bin/cp
这里我们把which cp的执行结果作为一个参数传递给ls命令,因此要想得到cp程序的输出列表,不必知道它完整的路径名。

我们不只限制于简单命令。也可以使用整个管道线(只展示部分输出):
$ file $(ls /usr/bin/* | grep zip)
/usr/bin/bunzip2: symbolic link to `bzip2'
....

在旧版shell程序中,有另一种语法也支持命令替换,可与刚提到的语法轮换使用。bash也支持这种语法。它使用倒引号来代替美元符号和括号:
$ ls -l `which cp`
-rwxr-xr-x 1 root root 71516 2007-12-05 08:58 /bin/cp

8.8 引用

shell提供了一种叫做引用的机制,来有选择地禁止不需要的展开。

8.9 双引号

我们将要看一下引用的第一种类型,双引号。如果你把文本放在双引号中,shell使用的特殊字符,除了$,\ (反斜杠),和`(倒引号)之外,则失去它们的特殊含义,被当作普通字符来看待。

这意味着单词分割,路径名展开,波浪线展开,和花括号展开都被禁止,然而参数展开,算术展开,和命令替换仍然执行。
$ echo "$USER $((2+2)) $(cal)"
me 4 February 2008
Su Mo Tu We Th Fr Sa
....

事实上,单词分割机制把换行符看作界定符,对命令替换产生了一个,虽然微妙,但有趣的影响。考虑下面的例子:
$ echo $(cal)
February 2008 Su Mo Tu We Th Fr Sa 1 2 3 4 5 6 7 8 9 10 11 12 13 14
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
$ echo "$(cal)"
February 2008
....

在第一个实例中,没有引用的命令替换导致命令行包含38个参数。在第二个例子中,命令行只有一个参数,参数中包括嵌入的空格和换行符。

8.10 单引号

如果需要禁止所有的展开,我们使用单引号。以下例子是无引用,双引号,和单引号的比较结果:
$ echo text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER
text /home/me/ls-output.txt a b foo 4 me
$ echo "text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER"
text ~/*.txt {a,b} foo 4 me
$ echo 'text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER'
text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER
正如我们所看到的,随着引用程度加强,越来越多的展开被禁止。

8.11 转义字符

经常在双引号中使用转义字符,来有选择地阻止展开。

$ echo "The balance for user $USER is: \$5.00"
The balance for user me is: $5.00

可以使用转义字符来消除文件名中一个字符的特殊含义。例如,在文件名中可能使用一些对于shell来说,有特殊含义的字符。这些字符包括"$", "!", "&"等字符。
$ mv bad\&filename good_filename

为了允许反斜杠字符出现,输入"\"来转义。注意在单引号中,反斜杠失去它的特殊含义,它被看作普通字符。

反斜杠转义字符序列

转义序列 意思
\a 响铃("警告"-导致计算机嘟嘟响)
\b 退格符
\n 新的一行。在类似Unix系统中,产生换行。
\r 回车符
\t 制表符

上表列出了一些常见的反斜杠转义字符。反斜杠表示法背后的思想来源于C编程语言,许多其它语言也采用了这种表示方法,包括shell。

echo 命令带上"-e"选项,能够解释转义序列。你可以把转义序列放在$' '里面。以下例子,使用sleep命令,一个简单的程序,它会等待指定的秒数,然后退出。我们可以创建一个简单的倒数计数器:
sleep 10; echo -e "Time's up\a"
我们也可以这样做:
sleep 10; echo "Time's up" $'\a'

Ch9: 键盘高级操作技巧

9.2 移动光标

光标移动命令

按键 行动
Ctrl-a 移动光标到行首。
Ctrl-e 移动光标到行尾。
Ctrl-f 光标前移一个字符;和右箭头作用一样。
Ctrl-b 光标后移一个字符;和左箭头作用一样。
Alt-f 光标前移一个字。
Alt-b 光标后移一个字。
Ctrl-l 清空屏幕,移动光标到左上角。clear命令完成同样的工作。

9.3 修改文本

文本编辑命令

按键 行动
Ctrl-d 删除光标位置的字符。
Ctrl-t 光标位置的字符和光标前面的字符互换位置。
Alt-t 光标位置的字和其前面的字互换位置。
Alt-l 把从光标位置到字尾的字符转换成小写字母。
Alt-u 把从光标位置到字尾的字符转换成大写字母。

9.4 剪切和粘贴文本

Readline的文档使用术语killing和yanking来指我们平常所说的剪切和粘贴。剪切下来的本文被存储在一个叫做剪切环(kill-ring)的缓冲区中。

剪切和粘贴命令

按键 行动
Ctrl-k 剪切从光标位置到行尾的文本。
Ctrl-u 剪切从光标位置到行首的文本。
Alt-d 剪切从光标位置到词尾的文本。
Alt-Backspace 剪切从光标位置到词头的文本。如果光标在一个单词的开头,剪切前一个单词。
Ctrl-y 把剪切环中的文本粘贴到光标位置。

9.5 自动补全

自动补全命令

按键 行动
Alt-? 显示可能的自动补全列表。在大多数系统中,你也可以完成这个通过按两次tab键,这会更容易些。
Alt-* 插入所有可能的自动补全。当你想要使用多个可能的匹配项时,这个很有帮助。

可编程自动补全
目前的bash版本有一个叫做可编程自动补全工具。可编程自动补全允许你(更可能是,你的发行版提供商)来加入额外的自动补全规则。通常需要加入对特定应用程序的支持,来完成这个任务。例如,有可能为一个命令的选项列表,或者一个应用程序支持的特殊文件类型加入自动补全。默认情况下,Ubuntu已经定义了一个相当大的规则集合。可编程自动补全是由shell函数实现的,shell函数是一种小巧的shell脚本,我们会在后面的章节中讨论到。如果你感到好奇,试一下:
set | less
查看一下如果你能找到它们的话。默认情况下,并不是所有的发行版都包括它们。

9.6 利用历史命令

bash维护着一个已经执行过的命令的历史列表这个命令列表被保存在你主目录下,一个叫做.bash_history的文件里。

9.7 搜索历史命令

浏览历史列表的内容:
$ history | less

$ history | grep /usr/bin
88 ls -l /usr/bin > ls-output.txt

数字 "88" 是这个命令在历史列表中的行号。随后在使用另一种展开类型时,叫做历史命令展开,我们会用到这个数字。我们可以这样做,来使用我们所发现的行:
$ !88
bash会把"!88"展开成为历史列表中88行的内容。

启动递增搜索,输入Ctrl-r,其后输入你要寻找的文本。当你找到它以后,你可以敲入Enter来执行命令,或者输入Ctrl-j,从历史列表中复制这一行到当前命令行。再次输入Ctrl-r,来找到下一个 匹配项(向上移动历史列表)。输入Ctrl-g或者 Ctrl-c,退出搜索。

历史命令

按键 行动
Ctrl-p 移动到上一个历史条目。类似于上箭头按键。
Ctrl-n 移动到下一个历史条目。类似于下箭头按键。
Alt-< 移动到历史列表开头。
Alt-> 移动到历史列表结尾,即当前命令行。
Ctrl-r 反向递增搜索。从当前命令行开始,向上递增搜索。
Alt-p 反向搜索,不是递增顺序。输入要查找的字符串,然后按下 Enter,执行搜索。
Alt-n 向前搜索,非递增顺序。
Ctrl-o 执行历史列表中的当前项,并移到下一个。如果你想要执行历史列表中一系列的命令,这很方便。

9.8 历史命令展开

通过使用"!"字符,shell为历史列表中的命令,提供了一个特殊的展开类型。我们已经知道一个感叹号,其后再加上一个数字,可以把来自历史列表中的命令插入到命令行中。

历史展开命令

按键 行动
!! 重复最后一次执行的命令。可能按下上箭头按键和enter键更容易些。
!number 重复历史列表中第number行的命令。
!string 重复最近历史列表中,以这个字符串开头的命令。
!?string 重复最近历史列表中,包含这个字符串的命令。

脚本
除了bash中的命令历史特性,许多Linux发行版包括一个叫做script的程序,这个程序可以记录整个shell会话,并把shell会话存在一个文件里面。这个命令的基本语法是:
script [file]
命令中的file是指用来存储shell会话记录的文件名。如果没有指定文件名,则使用文件typescript。查看脚本的手册页,可以得到一个关于script程序选项和特点的完整列表。

Ch10: 权限

10.1 拥有者,组成员,和其他人

可以用id命令,来找到关于你自己身份的信息:
$ id
uid=500(me) gid=500(me) groups=500(me)

当用户创建帐户之后,系统会给用户分配一个号码,叫做用户ID或者uid,然后,为了符合人类的习惯,这个ID映射到一个用户名。系统又会给这个用户分配一个原始的组ID或者是gid,这个gid可能属于另外的组。

用户帐户定义在/etc/passwd文件里面,用户组定义在/etc/group文件里面。当用户帐户和用户组创建以后,这些文件随着文件/etc/shadow的变动而修改,文件/etc/shadow包含了关于用户密码的信息。

对于每个用户帐号,文件/etc/passwd定义了用户(登录)名,uid,gid,帐号的真实姓名,主目录,和登录shell。如果你查看一下文件/etc/passwd和文件/etc/group的内容,你会注意到除了普通用户帐号之外,还有超级用户(uid 0)帐号,和各种各样的系统用户。

10.2 读取,写入,和执行

文件类型

属性 文件类型
- 一个普通文件
d 一个目录
l 一个符号链接。注意对于符号链接文件,剩余的文件属性总是"rwxrwxrwx",而且都是虚拟值。真正的文件属性是指符号链接所指向的文件的属性。
c 一个字符设备文件。这种文件类型是指按照字节流,来处理数据的设备。比如说终端机,或者调制解调器。
b 一个块设备文件。这种文件类型是指按照数据块,来处理数据的设备,例如一个硬盘,或者CDROM盘。

10.3 chmod-更改文件模式

Octal Binary File Mode
0 000 ---
1 001 --x
2 010 -w-
3 011 -wx
4 100 r--
5 101 r-x
6 110 rw-
7 111 rwx

虽然八进制到二进制的映射看起来不方便,但通常只会用到一些常见的映射关系:7(rwx),6(rw-),5(r-x),4(r--),and 0(---)。

chmod命令支持一种符号表示法,来指定文件模式。符号表示法分为三部分:更改会影响谁,要执行哪个操作,要设置哪种权限。通过字符“u”,“g”,“o”,“a”的组合来指定要影响的对象。

chmod 命令符号表示法

u “user”的简写,意思是文件或目录的所有者。
g 用户组。
o “others”的简写,意思是其他所有的人。
a “all”的简写,是“u”,“g”,和 “o”三者的联合。

如果没有指定字符,则假定使用“all”。执行的操作可能是一个“+”字符,表示加上一个权限,一个“-”,表示删掉一个权限,或者是一个“=”,表示只有指定的权限可用,其它所有的权限被删除。权限由“r”, w”,“x”来指定。

10.4 借助GUI来设置文件模式

10.5 umask 设置默认权限

当创建一个文件时,umask命令控制着文件的默认权限。umask命令使用八进制表示法来表达从文件模式属性中删除一个位掩码。

【这一小节书中讲的很详细,暂时用不到没有细看。】

10.6 更改身份

su命令允许你,假定为另一个用户的身份,以这个用户的ID启动一个新的shell会话,或者是以这个用户的身份来发布一个命令。sudo命令允许一个管理员设置一个叫做/etc/sudoers的配置文件,并且定义了一些具体命令,在假定的身份下,特殊用户可以执行这些命令。选择使用哪个命令,很大程度上是由你使用的Linux发行版来决定的。你的发行版可能这两个命令都包含,但系统配置可能会偏袒其中之一。

10.7 su 以其他用户身份和组ID运行一个shell

su [-[l]] [user]

如果包含"-l"选项,那么会为指定用户启动一个需要登录的shell。这意味着会加载此用户的shell环境,并且工作目录会更改到这个用户的主目录。这通常是我们所需要的。如果不指定用户,那么就假定是超级用户。注意(不可思议地),选项"-l"可以缩写为"-",这是经常用到的形式。启动超级用户的shell,我们可以这样做:su -

【在我首次使用这个命令 “su -” 的时候,提示:su: Authentication failure,网上查了一下,需要设定root密码,方法是运行 sudo passwd 命令。
su和sudo是有区别的,使用su切换用户需要输入所切换到的用户的密码,而使用sudo则是输入当前用户的密码。】

以这样的方式使用su命令,也可以只执行单个命令,而不是启动一个新的可交互的shell:

su -c 'command'

使用这种模式,命令传递到一个新shell中执行。把命令用单引号引起来很重要,因为我们不想命令在我们的shell中展开,但需要在新shell中展开。例如:su -c 'ls -l /root/*'

10.8 sudo 以另一个用户身份执行命令

sudo命令不要求超级用户的密码。使用sudo命令时,用户使用他/她自己的密码来认证。

sudo不会重新启动一个shell,也不会加载另一个用户的shell运行环境。这意味者命令不必用单引号引起来。注意通过指定各种各样的选项,这种行为也可以被override。

想知道sudo命令可以授予哪些权限,使用"-l"选项,列出所有权限:
$ sudo -l

默认情况下,Ubuntu不允许用户登录到root帐号(因为不能为root帐号设置密码),而是使用sudo命令授予普通用户超级用户权限。通过sudo命令,最初的用户可以拥有超级用户权限,也可以授予随后的用户帐号相似的权力。

10.9 chown 更改文件所有者和用户组

【跳过的,未细看】

10.10 chgrp 更改用户组所有权

【跳过的,未细看】

10.11 练习使用权限

【跳过的,未细看】

10.12 更改用户密码

【跳过的,未细看】

Ch11: 进程

11.1 进程是怎样工作的

init进程的PID总是1。内核也对分配给每个进程的内存进行跟踪。像文件一样,进程也有所有者和用户ID,有效用户ID,等等。

11.2 查看进程

默认情况下,ps不会显示很多进程信息,只是列出与当前终端会话相关的进程。TTY是"Teletype"的简写,是指进程的控制终端。TIME字段表示进程所消耗的CPU时间数量。

加上"x"选项(注意没有开头的"-"字符),告诉ps命令,展示所有进程,不管它们由什么终端(如果有的话)控制。在TTY一栏中出现的"?",表示没有控制终端。

STAT是"state"的简写,它揭示了进程当前状态:

进程状态

状态 意义
R Running 运行。这意味着,进程正在运行或准备运行。
S Sleeping 正在睡眠。进程没有运行,而是,正在等待一个事件,比如说,一个按键或者网络数据包。
D Uninterruptible Sleep 不可中断睡眠。进程正在等待I/O,比方说,一个磁盘驱动器的I/O。
T Stopped 已停止。已经指示进程停止运行。稍后介绍更多。
Z Zombie 一个死进程或“僵尸”进程。这是一个已经终止的子进程,但是它的父进程还没有清空它。(父进程没有把子进程从进程表中删除)
< high priority process 一个高优先级进程。这可能会授予一个进程更多重要的资源,给它更多的CPU时间。进程的这种属性叫做niceness。具有高优先级的进程是不好的(less nice),因为它占用了比较多的CPU时间,这样就给其它进程留下很少时间。
N low priority process 低优先级进程。一个低优先级进程(一个“好”进程)只有当其它高优先级进程执行之后,才会得到处理器时间。

另一个流行的选项组合是"aux"(不带开头的"-"字符)。

标题 意义
USER 用户ID。进程的所有者。
%CPU 以百分比表示的CPU使用率
%MEM 以百分比表示的内存使用率
VSZ 虚拟内存大小
RSS 进程占用的物理内存的大小,以千字节为单位。
START 进程运行的起始时间。若超过24小时,则用天表示。

11.3 用 top 命令动态查看进程

top程序连续显示系统进程更新的信息(默认情况下,每三分钟更新一次)

top程序接受一系列从键盘输入的命令。两个最有趣的命令是h和q。h,显示程序的帮助屏幕,q,退出top程序。

11.5 中断一个进程

在一个终端中,输入Ctrl-c,中断一个程序。这意味着,我们礼貌地要求终止这个程序。输入Ctrl-c之后,xlogo窗口关闭,shell 提示符返回。通过这个技巧,许多(但不是全部)命令行程序可以被中断。

11.6 把一个进程放置到后台(执行)

启动一个程序,让它立即在后台运行,我们在程序命令之后,加上"&"字符。

jobs 命令列出从终端中启动的任务。

11.7 进程返回到前台

使用fg命令,让一个进程返回前台执行。fg命令之后,跟随着一个百分号和工作序号(叫做jobspec)。如果我们只有一个后台任务,那么jobspec是可有可无的。

11.8 停止一个进程

使用fg命令,可以恢复程序到前台运行,或者用bg命令把程序移到后台。

输入 Ctrl-z 可以停止一个前台进程。

为什么要从命令行启动一个图形界面程序呢?有两个原因。第一个,你想要启动的程序,可能没有在窗口管理器的菜单中列出来(比方说 xlogo)。第二个,从命令行启动一个程序,你能够看到一些错误信息,如果从窗口系统中运行程序的话,这些信息是不可见的。有时候,一个程序不能从图形界面菜单中启动。这时候,应该从命令行中启动它。我们可能会看到错误信息,这些信息揭示了问题所在。一些图形界面程序还有许多有意思并且有用的命令行选项。

11.9 Signals

kill命令被用来“杀死”程序。

在使用Ctrl-c的情况下,会发送一个叫做INT(中断,Interrupt)的信号;当使用Ctrl-z时,则发送一个叫做TSTP(终端停止,Terminal Stop)的信号。

11.10 通过 kill 命令给进程发送信号

kill [-signal] PID...

如果在命令行中没有指定信号,那么默认情况下,发送 TERM(终止)信号。

常用信号

编号 名字 含义
1 HUP 挂起。这是美好往昔的痕迹,那时候终端机通过电话线和调制解调器连接到远端的计算机。这个信号被用来告诉程序,控制的终端机已经“挂起”。通过关闭一个终端会话,可以说明这个信号的作用。发送这个信号到终端机上的前台程序,程序会终止。许多守护进程也使用这个信号,来重新初始化。这意味着,当发送这个信号到一个守护进程后,这个进程会重新启动,并且重新读取它的配置文件。Apache网络服务器守护进程就是一个例子。
2 INT 中断。实现和 Ctrl-c 一样的功能,由终端发送。通常,它会终止一个程序。
9 KILL 杀死。这个信号很特别。鉴于进程可能会选择不同的方式,来处理发送给它的信号,其中也包含忽略信号,这样呢,从不发送Kill信号到目标进程。而是内核立即终止这个进程。当一个进程以这种方式终止的时候,它没有机会去做些“清理”工作,或者是保存劳动成果。因为这个原因,把KILL信号看作杀手锏,当其它终止信号失败后,再使用它。
15 TERM 终止。这是kill命令发送的默认信号。如果程序仍然“活着”,可以接受信号,那么这个信号终止。
18 CONT 继续。在停止一段时间后,进程恢复运行。
19 STOP 停止。这个信号导致进程停止运行,而没有终止。像KILL信号,它不被发送到目标进程,因此它不能被忽略。

既可以用号码,也可以用名字,不过要在名字前面加上“-”,来指定所要发送的信号。例如:kill -1 13546

其他常用信号

编号 名字 含义
3 QUIT 退出
11 SEGV 段错误。如果一个程序非法使用内存,就会发送这个信号。也就是说,程序试图写入内存,而这个内存空间是不允许此程序写入的。
20 TSTP 终端停止。当按下 Ctrl-z 组合键后,终端发送这个信号。不像 STOP 信号,TSTP 信号由目标进程接收,且可能被忽略。
28 WINCH 改变窗口大小。当改变窗口大小时,系统会发送这个信号。一些程序,像 top 和 less 程序会响应这个信号,按照新窗口的尺寸,刷新显示的内容。

11.11 通过 killall 命令给多个进程发送信号

给匹配特定程序或用户名的多个进程发送信号。

11.12 更多和进程相关的命令

其他与进程相关的命令

命令名 命令描述
pstree 输出一个树型结构的进程列表,这个列表展示了进程间父/子关系。
vmstat 输出一个系统资源使用快照,包括内存,交换分区和磁盘I/O。为了看到连续的显示结果,则在命令名后加上延时的时间(以秒为单位)。例如,“vmstat 5”。终止输出,按下 Ctrl-c 组合键。
xload 一个图形界面程序,可以画出系统负载的图形。
tload 与 xload 程序相似,但是在终端中画出图形。使用 Ctrl-c,来终止输出。

Ch12: shell 环境

12.1 什么存储在环境变量中?

Shell变量是由bash存放的少量数据,而环境变量基本上就是其它的所有数据。除了变量,shell也存储了一些可编程的数据,命名为别名和shell函数。

我们可以用bash的内部命令set,或者是printenv程序来查看什么存储在环境当中。

printenv命令也能够列出特定变量的数值:$ printenv USER

当使用没有带选项和参数的set命令时,shell和环境变量二者都会显示,同时也会显示定义的shell函数。

也可以通过echo命令来查看一个变量的内容:$ echo $HOME

如果shell环境中的一个成员既不可用set命令也不可用printenv命令显示,则这个变量是别名。用不带参数的alias命令来查看它们。

12.2 一些有趣的变量

环境变量

变量 内容
DISPLAY 如果你正在运行图形界面环境,那么这个变量就是你显示器的名字。通常,它是 ":0",意思是由X产生的第一个显示器。
EDITOR 文本编辑器的名字。
SHELL shell 程序的名字。
HOME 用户主目录。
LANG 定义了字符集以及语言编码方式。
OLD_PWD 先前的工作目录。
PAGER 页输出程序的名字。这经常设置为/usr/bin/less。
PATH 由冒号分开的目录列表,当你输入可执行程序名后,会搜索这个目录列表。
PS1 Prompt String 1,这个定义了你的shell提示符的内容。随后我们可以看到,这个变量内容可以全面地定制。
PWD 当前工作目录。
TERM 终端类型名。类似于Unix的系统支持许多终端协议; 这个变量设置你的终端仿真器所用的协议。
TZ 指定你所在的时区。大多数类似于Unix的系统按照协调时间时(UTC)来维护计算机内部的时钟,然后应用一个由这个变量指定的偏差来显示本地时间。
USER 你的用户名

12.4 如何建立 shell 环境?

有两种shell会话类型:一个是登录shell会话,另一个是非登录shell会话。登录shell会话会提示用户输入用户名和密码;例如,我们启动一个虚拟控制台会话。当我们在GUI模式下运行终端会话时,非登录shell会话会出现。

登录 shell 会话的启动文件

文件 内容
/etc/profile 应用于所有用户的全局配置脚本。
~/.bash_profile 用户私人的启动文件。可以用来扩展或重写全局配置脚本中的设置。
~/.bash_login 如果文件 ~/.bash_profile 没有找到, bash 会尝试读取这个脚本。
~/.profile 如果文件~/.bash_profile或文件~/.bash_login都没有找到,bash会试图读取这个文件。这是基于Debian发行版的默认设置,比方说Ubuntu。

非登录 shell 会话的启动文件

文件 内容
/etc/bash.bashrc 应用于所有用户的全局配置文件。
~/.bashrc 用户私有的启动文件。可以用来扩展或重写全局配置脚本中的设置。

除了读取以上启动文件之外,非登录 shell 会话也会继承它们父进程的环境设置, 通常是一个登录 shell。

在普通用户看来,文 ~/.bashrc可能是最重要的启动文件,因为它几乎总是被读取。非登录 shell 默认会读取它,并且大多数登录 shell的启动文件会以能读取~/.bashrc文件的方式来书写。

12.5 一个启动文件的内容

当我们想要在自己的主目录下,创建一个目录来存储我们自己的私人程序时,shell 已经给我们准备好了。我们所要做的事就是把创建的目录叫做bin。Ubuntu,在登录的时候,会检测目录~/bin是否存在,若找到目录则把它动态地加到PATH变量中。

export PATH这个export命令告诉shell让这个shell的子进程可以使用PATH变量的内容。

12.7 我们应该修改哪个文件来修改shell环境?

按照通常的规则,添加目录到你的PATH变量或者是定义额外的环境变量,要把这些更改放置到.bash_profile文件中(或者其替代文件中,根据不同的发行版。例如Ubuntu使用.profile文件)。对于其它的更改,要放到.bashrc文件中。除非你是系统管理员,需要为系统中的所有用户修改默认设置,那么则限定你只能对自己主目录下的文件进行修改。当然,有可能会更改/etc目录中的文件,比如说profile文件,而且在许多情况下,修改这些文件也是明智的,但是现在,我们要安全起见。

12.8 文本编辑器

GNOME自带了一个叫做gedit的编辑器。emacs编辑器最初由Richard Stallman写成。虽然emacs很容易获取,但是大多数Linux系统很少默认安装它。

12.9 使用文本编辑器

因为设计nano是为了代替由电子邮件客户端提供的编辑器的,所以它相当缺乏编辑特性。

Shell 脚本和 bash 启动文件都使用 "#" 符号来开始注释。

12.10 激活我们的修改

我们对于文件.bashrc的修改不会生效,直到我们关闭终端会话,再重新启动一个新的会话,因为.bashrc文件只是在刚开始启动终端会话时读取。然而,我们可以强迫bash重新读取修改过的.bashrc文件:$ source .bashrc

Ch13: vi简介

13.4 编辑模式

If you read the vim documentation, you will notice that (confusingly) command mode is called normal mode and ex commands are called command mode. Beware.

13.5 移动光标

光标移动按键

按键 移动光标
0 (零按键) 移动到当前行的行首。
^ 移动到当前行的第一个非空字符。
$ 移动到当前行的末尾。
w 移动到下一个单词或标点符号的开头。
W 移动到下一个单词的开头,忽略标点符号。
b 移动到上一个单词或标点符号的开头。
B 移动到上一个单词的开头,忽略标点符号。
Ctrl-f or Page Down 向下翻一页
Ctrl-b or Page Up 向上翻一页
numberG 移动到第number行。例如,1G移动到文件的第一行。
G 移动到文件末尾。

vi 中的许多命令都可以在前面加上一个数字,比方说上面提到的"G"命令。在命令之前加上一个数字,我们就可以指定命令执行的次数。例如,命令"5j"导致 vi 向下移动5行。

13.6 基本编辑

文本删除命令

命令 删除的文本
x 当前字符
3x 当前字符及其后的两个字符。
dd 当前行。
5dd 当前行及随后的四行文本。
dW 从光标位置开始到下一个单词的开头。
d$ 从光标位置开始到当前行的行尾。
d0 从光标位置开始到当前行的行首。
d^ 从光标位置开始到文本行的第一个非空字符。
dG 从当前行到文件的末尾。
d20G 从当前行到文件的第20行。

执行小 p 命令把剪切板中的文本粘贴到光标位置之后,或者是大 P 命令把文本粘贴到光标之前。

复制命令

命令 复制的内容
yy 当前行。
5yy 当前行及随后的四行文本。
yW 从当前光标位置到下一个单词的开头。
y$ 从当前光标位置到当前行的末尾。
y0 从当前光标位置到行首。
y^ 从当前光标位置到文本行的第一个非空字符。
yG 从当前行到文件末尾。
y20G 从当前行到文件的第20行。

大写的 J(不要与小写的 j 混淆了, j 是用来移动光标的) 把行与行之间连接起来。

13.7 查找和替换

Ch14:

Ch15:

Ch16:

Ch17:

Ch18:

Ch19:

Ch20:

Ch21:

Ch22:

Ch23:

Ch24:

Ch25:

Ch26:

Ch27:

Ch28:

Ch29:

Ch30:

Ch31:

Ch32:

Ch33:

Ch34:

Ch35:

Ch36:

Ch37: