GUIDE TO UNIX AND LINUX (8-13)

本文是一篇读书笔记。主要介绍了 Unix 手册和 shell 的使用。
我选择性忽略了原书一部分内容,将我认为重要的部分摘录于此。
本读书笔记适合有一定 Linux 基础的朋友参考。

这是一篇语雀副本,用于同步我的个人博客。
^本文目前仅在语雀个人博客发布发布,内容为作者 tou 原创,暂不允许全文转载。谢谢!

Chapter 8 一些程序的介绍

再次强调:Unix 不是一个具体的操作系统,而是一族操作系统(如 Linux、FreeBSD、Solaris 等)的总称。

which 命令:查看某程序是否存在

54004482-1A49-47B7-A2CB-11BD96E3A604.jpeg

如果使用的 shell 是 Bash,也可用 type 替代;如果使用的是 Korn shell 也可用 whence 命令替代。

由图可知,笔者使用的 centOS 7.0 默认使用的 shell 是 Bash

bc 命令:调用计算器程序

有些程序执行一项任务后就退出,有些程序会进入一个环境,在这个环境中通过一条条指令和程序交互。因此,当结束该程序的工作时,需要输入一个特殊的命令退出。我们以计算器程序命令 bc 为例:

D32FB0BD-B67D-47EA-B930-DC9DDE89F0CD.jpeg

8.12-8.16 介绍了计算器的详细用法。此略。

cal 命令:调用日历程序

  • cal + {month} + {year} : 显示本月日历并标出当前日期位置
  • cal -j + {month} + {year} : 同上,不过显示的内容不是当月日期号,而是当年日期号(可用查看是否是闰年)
  • cal + {year} + < | less> : 按页显示此年份的日历

724A99FE-72AB-4475-9074-CB8D444ECBE5.jpeg

可以查看一下 1752 年 9 月的日历,你会发现 9 月 2 日后就是 14 日。这跟当时世界上日历的修正有关。

Unix 中确实存在一个·日历提醒服务的程序,可以用 calendar 命令使用。略。

查看系统信息

9A97BEE9-536B-4EEB-AAA0-E8F83863857B.jpeg

uptime 命令

显示系统运行时间、当前登录的用户标识有几个、等待执行的程序数量(1 分钟、5 分钟、15 分钟)。

hostname 命令

显示计算机名称

uname 命令

显示操作系统名称。

使用 -a 选项(all information,全部信息),可以看到内核版本。

查看用户自身信息

whoami 命令

显示当前用户标识

quota 命令

我没能成功查看…

查看磁盘空间限制配额

查看其他用户信息

F4B31A3A-644C-42DD-A644-4658CE2967A1.jpeg

users 命令

显示当前登录系统的所有用户标识。

who 命令

显示用户标识、终端名称、登陆时间

w 命令

更详细的用户信息:who is doing what

也可以只查看某用户:w + {用户标识}

C6A29D2E-5C35-445F-B107-03E6A3EB032E.jpeg

Chapter 9 Unix 手册和 Info

RTFM

原意:”Read the fucking manual“(阅读该死的手册)

委婉一点:”Read the fine manual”(阅读精美的手册)

RTFM 表示的是 Unix 传统:在请求帮助之前尽最大的努力自己解决问题。比如阅读 Unix 联机手册(程序创建者会上传程序的文档资料)以及通过搜索引擎在 Internet 查找信息。

“I have RTFM’d for the last two hours, and I can’t figure out how to connect my cat to the Internet.”(其中 RTFM’d 表示 RTFM 的过去分词)

联机手册

man {命令名},manual 的缩写。

查阅 cp 命令(复制文件)的文档资料,输入 man cp
image.png

快捷键

可以查看 cp 的联机手册,它是按页(less)展示的,之前提到过,按 <Space> / <b> (或方向键)查看下一页 / 上一页。你还可以键入前缀 /? 进行查找。手册中更多的使用命令见下:

image.png

‘!’ is Bang

你可以同时打开两个终端,一个执行原先的任务,一个用来打开联机文档查阅说明。

但其实在查阅文档的时候,你可以键入前缀 ! 后输入一条 shell 命令并执行获得结果。我们称此处的 ! 为 “Bang”。

image.png

底部显示了运行的 shell 命令和结果。
文中 cp 被高亮了是因为之前执行了 /cp

你甚至可以在联机文档里再次查阅提及的其它联机文档。

指定节号

Unix 联机手册被分成 8 节内容:
image.png

当你使用 man kill 查阅 kill 命令时,你看到的是第 1 节中的 kill 内容:
image.png

默认情况下 man 假定我们参考第 1 节。

在最末尾,你会发现有一个 kill(2):
image.png

查阅特定节的说明:man 2 kill


这里我(centos 7)遇到了联机文档查阅不到 kill(2) 的问题,原因可能是没有安装完整 man-pages。

  1. 使用命令:sudo yum install man-pages
  2. 报错:could not resolve host: mirror…
  3. 自己 ping 了一下:ping www.baidu.com,发现确实网络连接有问题。
  4. 根据 CentOS7 更新 yum 报 Could not resolve host:mirrorlist.centos.org; Unknown error 解决办法,修改了/etc/sysconfig/network-scripts/ifcfg-ens33 文件,将 onBoot 改为 true,重新启动网络服务 service network restart
  5. 重新安装:sudo yum install man-pages
  6. 可以正常查阅了:man 2 kill

此时查阅到了第 2 节中的 kill
image.png

还有更多的查法,见 9.9,此略。
大多时候,我们只对第 1 节(命令)感兴趣,因此没必要指定节号。
当寻找与编程(2、3、4、5、7)或者系统管理(4、7、8)相关信息的时候才使用节号查询。

说明书页的格式

你会发现每一个说明书都按以下组织方式,这是因为有些说明书非常长,长到可以成为独立的参考手册。

image.png

whatis 命令:查看命令简介

whatis {命令1} {命令2} 仅展示说明书页的 Name 部分。

可以查看 1 条或多条命令的简介。

与之等价的命令是: man -f {命令1} {命令2}

image.png


这里我遇到 whatis 无法正常展示内容的情况。即 man time 显示了内容,但是使用 whatis time 不显示 Name 而是 “Nothing appropriate”.
原因是因为 whatis 命令本质是去索引一个数据库,有可能是我们刚刚更新了 manual,数据库还没来得及更新,此时我们可以手动更新数据库:

  • centOS 版本 < 7 时:sudo makewhatis
  • centOS 版本 ≥7 时:sudo mandb

参考:使用 whatis 命令时提示 nothing appropriatecentos whatis: nothing appropriate

apropos 命令:反向搜索

当你不清楚该使用哪个命令时,apropos 会尝试寻找说明页 Name 中匹配的单词。

该命令不区分大小写。

apropos 是法语,其重音在后,且 ‘s’ 不发音:a-pro-poe。在法语中等价 “related to”,在英语中作为前置词表示 “concerning”(关联意)。

与之等价的命令是:man -k {命令}

foo、bar 和 foobar

术语 foobar , foo , bar , baz 和 qux 经常在计算机编程或计算机相关的文档中被用作通用标识符(generic identifier)的名字。

当变量,函数,或命令本身不太重要的时候, foobar , foo , bar ,baz 和 qux 就被用来充当这些实体的名字,这样做的目的仅仅是阐述一个概念,说明一个想法。这些术语本身相对于使用的场景来说没有任何意义。

Foobar 经常被单独使用;而当需要多个实体举例的时候,foo,bar,和 baz 则经常被按顺序使用。

Info 系统

类似 Unix 联机手册,这个主要记录 GNU 实用工具。(因为许多类型的 Unix,包括几乎所有的 Linux 系统,都使用了 GNU 实用工具,详见第二章)

Info 有点类似早期的网页,里面充满可跳转的链接。其体系结构由 Richard Stallman (自由软件基金会和 GNU 项目创始人)设计的。

Indo 是 Texinfo 的一部分,后者是 GNU 项目的官方文档资料系统。

image.png
image.png

关于 info 更多的使用从 9.17 开始查看,此略。

Chapter 10 命令语法

一次输入多条命令

使用分号(;)隔开。注意:命令行行尾不需要分号。

image.png

命令语法

1
2
3
4
5
6
$ <command> + {option} + {argument}
$ <命令名称> + {选项} + {参数}

# 它们以空格间隔
# e.g.
ls -l file1 file2 file3

选项(options)有时候也被称为开关(Switches)或者标志(Flags)。

toulzx:
关于参数 argument 与 parameter,它们都有参数、变量意。
在编程中(主要是 C99 之后),习惯将 argument 定义为“实参”,将 parameter 定义为“形参”
如:现有函数 foobar(int foo, int bar){...},我们调用它 foobar(2, 3);。我们认为,前者里的 foobar 为形参(parameter),后者里的 23 为实参。
但在其它地方,它们的区别并不是非常明显。
我们也常认为方程 f(x) = 5x + 17 中的 x 就是参数(虽然在汉语里,我们更愿意称呼 x 为“变量”,而称 5 为参数)。
我认为这里不要带入中文的思维,统一使用英文看待。

语法规则:

  1. [方括号] 的项是可选的
  2. 不在 [方括号] 的项是必填的
  3. 黑体字是必须按原样准确键入的
  4. 斜体字必须用适当值替代(argument)
  5. 省略号(…)表示可任意重复多次
  6. 如果 [一个选项和一个参数] 组合在一起,那么该选项和参数必须同时使用
  7. 由竖线(|)字符分开的 [两个或多个项],表示可以从中选择一个项使用。

image.png
image.png

注意,这个规则在不同系统中有一点不同,如上 centOS 系统中用绿色来表示 argument

选项 -

选项顺序不重要。

1
2
3
4
5
6
ls -l -F file1

# 等价于
ls -F -l file1
ls -lF file1
ls -Fl file1

选项的大小写有区别!

1
2
3
4
ls -f file1

# 不等价于
ls -F file1

使用 man ls 可以查到这两个不同的选项:
image.png

可以尝试一下我们之前提到的 man -fman -k

选项 --

GNU 使用工具开发出来之后。

原有的选项由于设计为可组合,导致无法使用更长的选项(原来的不够用了)。

为不改变原有的选项,通过这种方式进行拓展。由于 Linux 使用 GNU 实用工具,所以会常见到这种 -- 的选项,而在其它大多数系统中,通常只有单字符的选项。

很多长选项的功能被设置得与短选项一致,便于记忆:

1
2
3
4
ls -r

# 等价于
ls --reverse

尽管确实存在一些奇葩的选项,但总归很少见。

当我们谈论选项时

在 20 世纪 90 年代中期之前学习 Linux 的,习惯将其称为 “minus”(相比于 “hyphen” 更容易表达),比如,ls -l 发音为 “L-S-minus-L”。

但在 Linux 文化中,我们常将连字符称为 “dash”,特别是年轻用户中。比如,ls --help 发音为 “L-S-dash-dash-HELP”。

Chapter 11&12&13 shell

shell 的历史略。

Bash 是目前最流行的 shell。

image.png

使用的是 Linux 登录的 shell 大概率是 Bash;如果使用的是商业版 Unix,登录的 shell 可能就是 Korn shell;如果使用的是 FreeBSD,那么登录的 shell 可能是 Tcsh。

如何改变登录的默认 shell,见 11.5-11.6,此略。

你还可以在 shell 中打开另一个 shell,并通过 exit 命令退回上一个 shell。

交互式 shell 和非交互式 shell

shell 既可以充当用户界面,也可以做为脚本解释器。

当根据 shell 提示输入命令 -> shell 处理命令 -> shell 返回提示,此时我们使用的是交互式 shell,shell 充当用户界面。

当我们创建一组命令(即 shell 脚本)并保存在文件中,运行脚本时,shell 从文件中读取命令,并且在不需要输入的情况下处理所有的命令。此时我们使用的就是非交互式的 shell。

环境、进程与变量

在进程运行过程中,它需要访问环境,即一组用来存放信息的变量。

变量,一组存储数据的实体(标识符和数据 || 变量名和值)。变量只有 4 中操作:

  • 创建
  • 查看
  • 修改
  • 销毁

在第 7 章中,我们使用了 echo $TERM 来查看系统使用终端的类型。常见的 TERM 值有 xterm、linux、vt100、ansi。

变量名可以用大小写字母、数字、下划线构成,且第一个字符不能是数字。全局变量通常习惯采用大写字母命名,而局部变量通常采用小写字母命名。

对于 shell 来说,变量几乎总数 hi 存储一种类型的数据:字符串。未赋值的变量拥有一个 null 值。

父进程和子进程

当我们在 shell 中启动了另一个程序,如 vi 文本编辑器。我们说一个进程 shell 启动了另一个进程 vi。其中,第一个进程称为父进程或双亲,第二个进程称为子进程或孩子。

在创建子进程的时候,系统为子进程复制了父进程的环境,我们称子进程继承了父进程的环境。这意味着:父进程可以访问到的所有的环境变量,子进程通通可以访问。

vi 能够访问到 shell 的环境变量 TERM,因此 vi 可以正确地格式化它的输出,以适应特定的终端。

Bourne shell 家族 与 C-shell

Bourne shell 家族:

  • Bash
  • Korn shell

C-Shell 家族:

  • C-Shell
  • Tcsh

提到这两个家族,是因为这两个家族的 shell 处理局部变量和全局变量时有不同。

局部变量和全局变量

shell 变量是创建它们的 shell 的局部变量。环境变量是全局变量。

严格从编程意义上来说,环境变量不完全是全局的,因为子进程对环境变量的修改不会传到父进程。

Bourne shell 家族中,shell 变量也默认是是大写的(和环境/全局变量一样)。C-shell 则没这种习惯。

对于大多数编程语言,变量或是局部的、或是全局的,但 shell 不是这样,有些变量同时拥有局部变量和全局变量的含义!(有些变量对于 shell 有用,应该是局部变量,但同时对于 shell 的启动进程也有作用,这又应该是环境变量)

Bourne shell 的处理方式是将变量只定义为如下两种形式:

  • 局部变量
  • 既是局部变量又是全局变量

也就是说,Bourne shell 没有一个只属于环境变量的变量!

1
2
3
4
5
# 创建局部变量 HAPPYLINUX
HAPPYLINUX = cool

# 将局部变量导出到环境,称为“局部+全局”变量。
export HAPPYLINUX

C-shell 家族中,环境变量通过命令 setenv 创建,并以大写命名;shell 变量由 set 命令创建,并且以小写字母命名。

为了解决上面提到的特殊变量(既是局部变量又是全局变量)的问题,C-shell 定义了少数几个特殊的 shell 变量,分别绑定到对应的环境变量,当其中一个被修改后,另一个会自动修改。

常见的双名称变量:

shell 变量 环境变量 含义
cwd PWD 当前/工作目录
home HOME home 目录
path PATH 搜索程序的目录
term TERM 正在使用的终端类型
user USER 当前用户标识

cwd 和 PWD 这个组合确实有点奇葩:
cwd: current/working directory
PWD(pwd): print working directory
pwd 来源于最初的 Unix 命令,那是一个计算机输出真正打印在纸张上的时代。

显示环境变量:envprintenv

env | less | sort

显示 shell 变量和它们的值:set

Bourne shell 家族中你看到的变量名都是大写的,C-shell 家族中则是小写。

在 Bourne shell 中如何确定一个“局部+全局”变量

奇怪但真实:比较 envset 的输出…

显示(一个)变量并使用它的值:echo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
echo I Love PCA
# shell 输出:I Love PCA

echo $TERM
# shell 输出:linux(我使用的是 centos 7)

echo ${TERM}
# 与上例等价

echo I Love PCA and $TERM
# shell 输出:I Love PCA and linux

echo I created a new shell called PCA-${TERM}
# shell 输出:I created a new shell called PCA-linux

echo 默认后面的是一串字符串的值,因此用 $ 符(dollar)表示后面的变量。

${} 的表示方法允许变量与字符串不分隔显示。

元字符

<> 是元字符(第 15 章),表示重定向。

4627C1AD-2000-449E-8B1B-F24F0B2BADE4.jpeg

echo 的更多用法

显示多个变量的值:

1
echo $HOME $TERM $PATH $SHELL

在 Korn shell 中,你还可以使用 print 代替 echo,以前为了兼容不同系统,现在不需要了。

在 Bourne shell 家族使用变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 创建/修改局部变量
# 注意:等号两侧不能加空格!
MY_NAME=toulzx
MY_DETAIL="I'm a boy."

# 局部变量 -> “局部+全局” 变量
# 或直接创建“局部+全局变量”
export MY_NAME MY_DETAIL MY_LOVE=PCA

# 销毁变量是从环境中移除变量的唯一方法
unset MY_NAME MY_DETAIL MY_LOVE

# 你可以使用此命令查看他们的内容
echo $MY_NAME $MY_DETAIL $MY_LOVE

06AF504E-8090-4469-BF48-90541859AB76.jpeg

在 C-Shell 家族使用变量

setenv :

1
2
3
4
5
setenv MY_NAME toulzx
setenv MY_DETAIL "I'm a boy."
setenv PATH /usr/local/bin:/usr/bin:/bin

unsetenv MY_NAME MY_DETAIL

注意:有空格,没有等号!

set :

1
2
3
4
set his_name=VanPCA
set path={/usr/bin /bin /usr/ucb}

unset his_name path

注意:有空格、有等号!
注意:区分将变量设为空(null)和删除变量。

shell 选项

Bourne shell 家族根据 shell 选项设置交互方式。

你可以使用 set +oset -o 查看 shell 选项。

略。

机器可读(machine-readable)和人类可读(human-readable)

机器可读是指以适合程序的方式输出,比如对于一串数据,以逗号分隔的一串字符串显然适合程序输出。尽管我们难以阅读。

比如 set +oset-o

GNU 实用工具很多都提供了人类可读的选项。

命令和定制

元字符

我们使用分号; 在一行中分隔各条命令,实现同一个命令行上多条命令的执行。因此分号对 shell 有特殊的含义,所以它就是一个元字符。

shell 中使用的元字符:

image.png

引用和转义

使用转义字符 \ 引用字符

1
echo The search path is $PATH\; the shell is $SHELL.

我们通过转义字符进行“引用”,被“引用”的字符不再发挥元字符的作用,而是作为普通字符使用。

使用单引号 ' 引用一串字符串(除了 <Return><Tab><Space>

1
2
3
4
5
6
7
8
9
10
11
12
13
# 示例:It is warm (and sunny); come over & visit.

# 如果只使用转义字符
echo It is warm \(and sunny\)\; come over \& visit.

# 使用单引号
echo 'It is warm (and sunny); come over & visit.'

# 可以混合使用
echo It is warm '(and sunny);'come over \& visit.

# 但不能这样,单引号会转义反斜线,不要想着负负得正,我猜没人这么无聊吧...
echo It is warm '(and sunny)\;'

当使用单引号进行“引用”的时候,被引用的字符串内所有的字符全部被转义,不再发挥元字符的作用。

使用双引号 " 引用一串字符串(除了 $、```、\<Return><Tab><Space>

1
echo "My userid is <$USER>; my terminal is<$TERM>"

双引号会“引用”字符串中的所有内容,除了 $、```、\

强引用与弱引用

单引号比双引号功能更强,称单引号为强引用(strong quote),双引号为弱引用(weak quote)。

反斜线(转义字符)比单引号、双引号都要强。

但单引号还是会使反斜线被“引用”,不要误会下面的例子:

1
2
3
4
5
6
# 转义字符并不会转义。
# 我可不可以认为,是因为约定了由外到内的识别呢?
echo It is warm '(and sunny)\;'

# 转义字符可以转义单引号
echo It\'s warm outside.

新行字符的引用

反斜线甚至可以(立刻)转义新行字符 <Return> ,意味着,你可以在命令行中实现换行输入,这在一条命令十分长的时候很有用。(toulzx: 比如炼丹的时候!!)
image.png

相比之下,未结束的单引号会等待匹配,在此之前的新行字符都将生效。
image.png

以上是 Bourne shell 家族的处理方式,如果是 C-Shell 家族,第一次回车就会报错了(缺少匹配)。

内部命令与外部命令

内部命令是少数的。

内部命令一般没有自己的说明书页,其包含在 shell 发说明书页中。

或者使用 type 命令查看。

image.png

使用内部 help 命令快速查看关键字的语法

1
2
3
4
5
6
7
8
9
10
help -s case
help -s for
help -s function
help -s if
help -s select
help -s time
help -s while
help -s until

# -s 表示展示简略内容

image.png

外部命令与搜索路径

date 是一条外部命令。当我们输入 date 命令的时候,shell 会去寻找 date 程序,然后,运行它。

shell 通过检查环境变量 PATH 去寻找程序,PATH 包含一系列目录的名称,我们称其为搜索路径。你可以使用 echo $PATH 查看 PATH 变量。

PATH:存放程序的目录:搜索路径

shell 查找外部命令时,会寻找一下路径的程序:

1
2
3
4
5
6
7
8
# 存放系统中供所有用户使用的程序,Unix 安装时自动设置
/bin
/usr/bin
/usr/ucb ## 存放派生自伯克利 Unix 的程序,某些系统才有

# 定制目录
/usr/local/bin ## 由管理员设置,存放为了本地使用而安装的程序
/home/toulzx/bin ## 用户 toulzx 的 /bin 目录,存放 toulzx 自己使用的程序

在 Bourne shell 家族中,你可以这样修改搜索路径:

1
2
3
4
5
6
# export 使变成“全局+局部”变量
# 使用冒号间隔不同路径,并且两侧无空格!
export PATH="/bin:/usr/bin:/usr/ucb:/usr/local/bin"

# 如果仅是在原有的基础上,末尾添加位于本用户下的 /bin (/home/toulzx/bin)中
export PATH="$PATH:$HOME/bin"

在 C-Shell 家族中,你可以这样修改搜索路径:

1
2
3
4
5
6
# 设置局部变量 path 会自动设置全局变量 PATH
# 等号、大括号包裹、不同路径用空格分隔
set path={/bin /usr/bin /usr/ucb /usr/local/bin}

# 如果仅是在原有的基础上,开头添加位于本用户下的 /bin (/home/toulzx/bin)中
set path={$HOME/bin $path}

路径添加的顺序决定了 shell 检查的顺序,shell 会运行找到的第一个程序。

一般都会把用户自己的路径往后放。
确保搜索路径中不包含工作目录,或者其它用户可能访问的其它任何目录。
这常常是黑客创建后门的技巧:寻找一种会以 root 账户运行的程序,并修改它。当 root 账户下一次运行的时候,就会利用权限创建秘密文件(后门),使用这个文件就可以为黑客获得超级用户的访问权限。

修改 shell 提示

常用于 shell 提示的环境变量
image.png

对于 Bourne shell 家族,需要修改名为 PS1 的环境变量。

PS1: prompt for the shell, number 1
还存在类似的 PS2,PS3,PS4,这里不需要用到。

1
2
3
4
5
6
export PS1="% "

# 使用变量的值
export PS1="${USER}$"
export PS1='Lucky Number ${RANDOM} $'
export PS1='Working time: ${SECONDS}s $'

对于 C-Shell 家族,需要修改名为 prompt 的 shell 变量。

1
2
3
4
5
6
set prompt = "% "

# 使用变量的值
set prompt = "${USER}%"
set prompt = 'Lucky Number ${RANDOM} %'
set prompt = 'Working time: ${SECONDS}s %'

引用变量使用什么引号

1
export PS1="${USER}$"
1
export PS1='Lucky Number ${RANDOM} $'

你是否发现,上方两个例子使用的不同的引用符号(单引号和双引号)。根据之前所学,双引号允许将 $ 解释为元字符,而单引号会“引用”该符号。

换句话说,双引号" 的弱引用意味着 shell 处理该命令的时候就将用变量的值替换字符串中的变量了,而单引号 ' 强引用使 $ 符号被保留下来,直到实际创建 shell 提示的时候才对变量 $ 求值。

toulzx: 是不是可以这样的理解:shell 对字符串中元字符的处理,发生了两次:第一次是创建时,第二次是使用时。

使用转义字符的特殊码

只有 Bourne shell 家族的 bash 和 C-Shell 家族的 Tcsh 允许使用特殊码。

特殊码允许在 shell 提示中插入颜色、字体形式、工作目录名称等信息。

image.png

其中有些特殊码和环境变量的设置有相同效果(bash 为例):

1
2
3
4
export PS1="\u $"

# 等价于
export PS1="${USER} $"

image.png

toulzx:
如图,我的默认 shell 提示由 <用户标识> + <计算机主机名> + <当前工作目录(基名)> 组成。
由于 Bash 中没有完整工作目录的特殊码,但没关系,我们可以使用环境变量代替:$PWD

使用反引号 ``` 进行命令替换

command substitution

允许在一条命令中嵌入另一条命令,并用输出替换该命令,最后 shell 再执行整个命令。(嵌套,由内而外执行)

image.png

显然,单引号会使反引号被“引用”。

注意:date 是命令不是变量。

历史列表

回顾以下知识点:

  • 使用 <Bachspace> 删除键入的最后一个字符(光标处),发送 erase 信号。
  • 使用 ^WCtrl + W)删除键入的最后一个单词,发送 werase 信号。
  • 使用 ^U^X 删除整行,发送 kill 信号。
  • 使用 stty 命令显示系统上所有键映射。
  • 使用左右方向键移动光标,上下方向键选择历史命令。(仅 Bash 支持)

输入命令时,你应该遵循此原则:重用,而不是重新键入。

查看历史列表

无论正确错误的历史命令都会被记录,且 shell 会给它编号。

Bourne shell 家族常用 fc 命令。

C-Shell 家族常用 history 命令或 ! 命令。

Bash 支持 C-Shell 的历史列表命令。

1
2
3
# 按页显示
fc | less
history | less

执行上一条命令:

1
2
fc -s
!!

toulzx: 书 P269 最后一行把 fc 写错成 fs 了

执行指定编号的命令:

1
2
3
# 执行编号 208 的命令
fc -s 208
!208

修改指定编号的命令再执行:

1
2
3
4
5
6
7
8
9
10
# 现已有编号为 208 的命令如下:
echo $PS1


# 现在改为查看环境变量 SHELL 的值:
## fc -s {pattern}={replacement} {number}
## ! {number}:s/{pattern}/{replacement}

fc -s PS1=SHELL 208
! 208:s/PS1/SHELL/

因此当你不小心执行了内容错误的命令内容时:

1
2
3
4
5
6
# 上一条不小心输错的命令是 `date`:
datq

# 修改并重新执行
fc -s q=e
^q^e ## C-Shell 有点不同

缝合怪 Bash 占尽优势

Bash 支持两个家族所有的历史记录的命令,所以建议使用 history/!

Bash 额外支持 ^R 命令,按下后,输入字符串,可以自动查找最近使用的、包含字符串内容的命令。

设置历史记录存储值

Bourne shell 家族修改环境变量 HISTSIZE:

1
export HISTSIZE=50

C-Shell 家族修改 shell 变量 history:

1
set history = 50

将历史列表的事件编号显示在 shell 提示中

1
2
3
4
5
6
# 如:`[208]$`

## Bash
export PS1="[\!]$"
## Tcsh
set prompt = "[%\!]%"

你可能注意到 Tcsh 的命令中多了一个反斜线,这是因为反斜线和右括号相邻会有问题,此问题难解,不用关心。

自动补全

涉及变量、文件名、路径名…
image.png

命令的别名

自定义简化的命令,代替常用的、复杂的命令。

现假设我们经常使用这条命令:ls -l temp*,我们希望每次输入 lt 就可以调用这条命令。

查看别名:alias

使用 alias 命令可以查看所有的别名。

使用 type {commands} 命令可以查看某条命令是不是别名。

创建别名:alias {name}={commands}

1
2
3
4
5
6
7
8
9
# Bourne shell 家族:alias {name}={commands}
alias lt='ls -l temp*'
alias ls="ls -l"
alias a=alias

# C-Shell 家族(没有 "="):alias {name} {commands}
alias lt 'ls -l temp*'
alias ls "ls -l"
alias a alias

这里使用了强引用的单引号包裹命令,是因为命令中包含了多个空格和元字符(*),单引号保留了元字符的含义,直到别名执行。

移除别名:unalias {name}

1
2
unalias lt
unalias a

别名和已有命令重复

使用转义字符(\)使用原有命令。

1
2
3
4
5
6
7
alias ls="ls -l"

# 执行 "ls -l"
ls

# 执行原始命令
\ls

别名示例:避免删错文件

当我们打算删除所有匹配特定模式的文件之前,我们一定要养成检查的习惯,因为该过程不可逆!

即,在执行 rm temp* extra? 之前,应该先执行 ls temp* extra?

当我们执行了 ls temp* extra? 并确认后,我希望通过别名 del 完成 rm temp* extra?

1
2
3
alias del='fc -s ls=rm'
# 或
alias del='rm \!ls:*'

作者

tou

发布于

2021-12-20

更新于

2021-12-20

许可协议

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×