主要是学习 Vim 编辑器,要知道自己重点放在哪里!
命令 | 作用 |
---|---|
printenv | 显示部分或全部环境变量 |
set | 显示 Shell 变量和环境变量 |
echo | 查看变量内容 |
slias | 查看命令别名 |
Shell 在环境中保存了两种基本类型数据,它们分别是环境变量和 Shell 变量,但是在 Bash 中,Bash 将一部分数据存放在 Shell 变量中,其他数据则存放在环境变量中,这两种数据基本上没有区别。除变量之外,Shell 还保存了一些程序化数据,也就是别名和 Shell 函数。
想要检查环境,可以使用内建命令 set
或 printenv
,不过由于环境内容相当冗长,建议将其输出结果通过管道传给 less
命令:printenv | less
,另外,printenv
命令还可以列出指定环境变量的值:printenv USER
。set
命令在不加任何选项和参数的时候会显示 Shell 变量、环境变量以及已定义的 Shell 函数,不同于 printenv
命令的是,set
命令输出结果是按照字母顺序排序的。也可以使用 echo
命令查看变量内容:echo $HOME
。
一些值得注意的环境变量:
变量 | 内容 |
---|---|
DISPLAY | 屏幕(display)名称(如果启用了图形化环境),通常为0,代表服务器生成的第一个屏幕 |
EDITOR | 用于文本编辑的程序名称 |
SHELL | Shell 程序名称 |
HOME | 主目录的路径名 |
LANG | 定义了字符集及其所使用语言的排序方式 |
OLDPWD | 先前的工作目录 |
PAGER | 用于对输出结果进行分页的程序名称,通常设置为 /usr/bin/less |
PATH | 由冒号分隔的目录列表,Shell 会在其中搜索用户输入的可执行程序名称 |
PS1 | “提示字符串1”(prompt string 1)的缩写,定义了 Shell 提示符的内容,定制性很强 |
PWD | 当前工作目录 |
TERM | 终端类型名称 |
TZ | 指定时区 |
USER | 用户名 |
用户登录系统后,Bash 程序会启动并读取一系列称为启动文件的配置脚本,这些脚本定义了所有用户共享的默认环境。接着读取主目录中定义个人环境的多个启动文件。确切的顺序取决于启动的 Shell 会话类型。
登录 Shell 会话读取的启动文件:
文件 | 内容 |
---|---|
/etc/profile | 应用于所有用户的全局配置脚本 |
~/.bash_profile | 用户的个人启动文件,可用于扩展获覆盖全局配置脚本中的设置 |
~/.bash_login | 如果没有找到 ~/.bash_profile,Bash 会尝试读取该脚本 |
~/.profile | 如果 ~/.bash_profile 和 ~/.bash_login 都没有找到,Bash 会尝试读取该文件 |
非登录 Shell 会话读取的启动文件:
文件 | 内容 |
---|---|
/etc/bash.bashrc | 应用于所有用户的全局配置脚本 |
~/.bashrc | 用户的个人启动文件,可用于扩展获覆盖全局配置脚本中的设置 |
我们来看一个典型的 .bash_profile 文件(取自 CentOS 7 系统):
第二和第三个注释的汉译为:获取别名和函数;用户特定的环境和启动程序。因为参考书使用的是 CentOS 6 系统,跟自己的配置也好像不太一样,所以书上的 PATH 变量一行是这样的:PATH=$PATH:$HOME/bin
,后面也照着这个 PATH 变量来吧,这样好说一点。
文件里的 if 复合命令目前可以这样理解:
if the file "~/.bashrc" exists, then read the "~/.bashrc" file.
从这几行 if 复合命令的代码中可以看出登录 Shell 会话是如何获取 .bashrc 内容的,而接下来便是要处理 PATH 变量。
在命令行上输入命令后,Shell 是怎样找到这些命令的?例如,当用户输入 ls 命令,Shell 并不会翻遍整个系统来查找 /bin/ls(ls 命令的完整路径),而是搜索 PATH 变量中保存的目录列表。
为了能够更好的理解 PATH 变量,我们先来演示一个参数扩展工作方式的具体例子:
利用这项技术,我们可以将文本追加到变量现有内容之后,也就是说,通过将字符串 $HOME/bin 添加到 PATH 变量内容的尾部,当输入命令时, $HOME/bin 目录就会处于被搜索的路径列表中。这意味着如果我们想在主目录中创建一个用于存放个人私有程序的子目录,Shell 也会将其纳入搜索范围,我们需要做的只是将该子目录命名为 bin。
注意:很多系统默认提供的就是这种 PATH 变量,基于 Debian 的系统绘制登录时测试 ~/bin 目录是否存在,并动态地将其加入 PATH 变量中(如果存在的话)。
最后是这一句export PATH
,export 命令告诉 Shell,使 PATH 变量的内容可用于该 Shell的子进程。
以下是对环境变量的补充说明:① $HOME 这个代码是一个环境变量,它代表的是当前登录的用户的主文件夹的意思(就是家目录的那个);② $HOME/bin 这个代码指的就是主文件夹下的bin子目录,代表的是文件夹的内部子目录(注意不是根目录的那个);③ PATH=PATH:HOME/bin 这个代码是设置PATH环境变量,就是设置环境变量用等号(冒号:是分割符);④ PATH:HOME/bin 表示在保留原来的PATH环境变量的基础上,再增加 HOME/bin 这个路径作为新的 $PATH 环境变量(计算机中的变量有许多,主要应用于系统文件的管理方面)
只要知道了启动文件在哪里,文件中包含了什么内容,我们就可以对其做出修改并自定义环境了。一般来说,在 PATH 变量中添加目录或者定义额外的环境变量,这些改动应放入 .bash_profile 中,其他改动则放在 .bashrc 中。为了编辑(也就是修改)Shell 的启动文件和系统中的其他大多数配置文件,我们要用到一个称为文本编辑器的程序。在命令行输入文本编辑器的名称,后面跟上待编辑的文件名就可以调用文本编辑器。如果指定的文件尚不存在,文本编辑器则会创建一个新文件,如使用图形化编辑器 gedit:gedit some_file
。
图形化编辑器一目了然,我们应该吧注意力放在文本化编辑器 Nano 身上。当我们准备启动 Nano,编辑 .bashrc 文件之前,还最好做好备份工作:cp .bashrc .bashrc.bak
(.bak、.sav、.old、.orig 都是常见的备份文件扩展名)。启动 Nano:nano .bashrc
,Nano 启动好之后,我们会看到以下内容:
名目显示内容分为 3 个部分:顶部的标题、中间的可编辑文本和底部的命令菜单(^ 表示的是 Ctrl-,例如,Ctrl-X 是退出编辑器,Ctrl-O是保存)。使用下方向键或者下翻页键将光标移动到文本的末尾,然后在 .bashrc 文件中添加以下几行内容:
umask 0002
export HISTCONTROL=ignoredups
export HISTSIZE=1000
alias l.=‘ls -d .* --color=auto’
alias ll=‘ls -l --color=auto’
本身系统的 .bashrc 文件中可能已经包含了这些内容,不过就算重复也不会造成什么不良影响。
.bashrc 文件中添加的内容含义:
行 | 含义 |
---|---|
umask 0002 | 设置掩码,解决共享目录问题 |
export HISTCONTROL=ignoredups | 使 Shell 的历史记录特征忽略已经记录过的相同命令 |
export HISTSIZE=1000 | 将命令历史记录的数量从默认的 500 行增加到 1000 行 |
alias l.=‘ls -d .* --color=auto’ | 创建名为 l. 的新命令,该命令能够显示以点号开头的所有目录条目 |
alias ll=‘ls -l --color=auto’ | 创建名为 ll 的新命令,该命令能够以长格式显示目录条目 |
修改完以后,按 Ctrl-O 组合键保存当前的 .bashrc 文件,然后按 Ctrl-X 组合键退出 Nona(保存退出前最好在其中添加一些注释来帮助理解)。
因为尽在 Shell 会话启动时才会读取 .bashrc 文件,所以对其做出的改动只有在关闭终端会话并再次打开新会话的时候才会生效,不过我们也可以强制 Bash 重新读取修改后的文件:source ~/.bashrc
,在这之后就可以看到改动生效了。
看到这里,应该明白了虽然标题是 vi 入门,其实还是学习 vim 哈哈。
使用命令 vi 或 vim 均可进入 vim:
输入命令 :q
退出 vi(冒号也是命令的一部分),如果由于某些原因,vi 未能退出(通常是修改了文件但没有保存),可以加上叹号强制退出(:q!
)。刚进入的时候我们处于命令模式,而如果我们在 vi 中迷路,搞不清当前所处模式,连按两次 Esc 键就可以返回命令模式。
再次启动 vi,这次使用一个并不存在的文件名作为参数来创建一个新文件:vi foo.txt
,刚一进去是命令模式(command mode),要想在文件中添加文本,还须使用 i 键切换为插入模式(insert mode)。文本输入完毕,冒号:加w键保存即可。
在命令模式下的光标移动命令:
命令 | 光标移动 |
---|---|
l 或右方向键 | 向右移动一个字符 |
h 或右方向键 | 向左移动一个字符 |
j 或右方向键 | 向下移动一行 |
k 或右方向键 | 向上移动一行 |
数字 0 | 移动到当前行行首 |
^ | 移动到当前行中第一个非空白字符处 |
$ | 移动到当前行行尾 |
w | 移动到下一个单词开头或标点符号 |
W | 移动到下一个单词开头,或略标点符号 |
b | 移动到上一个单词开头或标点符号 |
B | 移动到上一个单词开头,或略标点符号 |
Ctrl-F 或下翻页键(Page Down) | 移动到下一页 |
Ctrl-B 或上翻页键(Puge Up)或 b | 移动到上一页 |
数字键 G | 移动到指定行(例如 1G 可以使光标移动到文件的第一行) |
G | 移动到文件的最后一行 |
像命令 G 一样,许多 vi 命令的前面都可以加上数字前缀,通过数字来指定命令执行的次数,例如 5j 可以使光标下移 5 行。
值得一提的是,vi 提供了有限形式的撤销操作:如果在命令模式下按下 u 键,vi 会撤销上一次做出的改动,非常方便。
除了使用 i 命令插入文本,我们也可以先把光标移动到行尾,再使用 a 命令实现追加,或者不动光标直接使用 A 命令。
插入文本的另一种方法是新建,这可以在已有的两行之间插入一个空行并进入插入模式
,新建命令有两种如下:
命令 | 新建内容 |
---|---|
o | 在当前行之下新建一行 |
O | 在当前行之上新建一行 |
关于删除文本,vi 也提供了多种方法。首先,x 命令会删除光标处的字符,x 之前可以使用数字来指定删除多少个字符。d 命令更加通用(而且和 x 一样,也可以在其之前使用数字来指定删除次数),且 d 命令之后还可以跟上移动命令,控制删除范围),以下给出了一些示例:
命令 | 删除内容 |
---|---|
x | 当前字符 |
3x | 当前字符和接下来的两个字符 |
dd | 当前行 |
5dd | 当前行和接下来的4行 |
dW | 从光标所在处一直到下一个单词开头 |
d$ | 从光标所在处一直到行尾 |
d0 | 从光标所在处一直到行首 |
d^ | 从光标所在处一直到行中的第一个非空白字符 |
dG | 从当前行一直到文件末尾 |
d20G | 从当前行一直到地 20 行 |
关于剪切、复制及粘贴。d 命令不仅能够删除文本,还可以“剪切”文本,每次使用 d 命令,被删除的文本就会被复制到粘贴缓冲区(paste buffer),可将其想象成粘贴板,随后可以使用 p 命令将粘贴缓冲区中的内容粘贴到光标之后或之前。y(yank)命令可用于“复制文本”,其实用方法和用于剪切文本的 d 命令差不多,以下是一些示例:
命令 | 复制内容 |
---|---|
yy | 当前行 |
5yy | 当前行和接下来的4行 |
yW | 从光标所在处一直到下一个单词开头 |
y$ | 从光标所在处一直到行尾 |
y0 | 从光标所在处一直到行首 |
y^ | 从光标所在处一直到行中的第一个非空白字符 |
yG | 从当前行一直到文件末尾 |
y20G | 从当前行一直到地 20 行 |
关于合并,vi 对行的约束相当严格,是无法通过将光标移至行尾再删除行尾字符来合并当前行与下一行的,不过可以使用特殊命令 J (小写 j 是光标移动命令)来实现。
f 命令可以在行内搜索并将光标移动至指定字符的下一次出现处(例如 fa
会将光标移动至字符 a 在行内下一次出现的位置),输入分号可以重复先前的搜索。/ 命令可以将光标移动至指定单词或短衣的下一次出现处,使用 n 命令来重复上一次搜索。
vi 使用 ex 命令可以在若干行或整个文件范围内执行搜索和替换操作,例如想要将文件中所有单词 Line 改为 line,可以输入命令:%s/Line/line/g
,下面是对其命令的拆解:
组成 | 含义 |
---|---|
: | 冒号表示接下来是 ex 命令 |
% | 指定操作的行范围 |
s | 指定操作,这里是替换(substitution)操作 |
/Line/line/ | 指定搜索模式和替换文本 |
g | 代表全局(global),表示对行中所有搜索字符执行替换操作 |
使用 % 时也可以将该范围写作1,5(一共5行)或者1,$(表示从第一行到最后一行),如果未指定行范围,则仅对当前行执行操作;如果不指定 g,则仅替换每行搜索到的第一个字符串。
我们也可以要求在替换的时候由用户进行确认,着只需在命令结尾加上 c 即可,确认选项有如下所示:
选项 | 操作 |
---|---|
y | 执行替换 |
n | 跳过此次替换 |
a | 执行所有替换 |
q 或 Esc | 退出替换 |
l | 执行此次替换,然后退出 |
Ctrl-E / Ctrl-Y | 分别表示向下滚动和向上滚动(可用于查看被替换处的上下文) |
我们可以使用 vi 打开多个文件进行编辑 vi file1 file2 file3
,使用 ex 命令切换文件 :bn
(buffer next)切换到下一个文件,:bp
(buffer previous)切换到上一个文件(必须先保存再切换,如若放弃修改需要在命令后面添加叹号 ! 强制执行)。我们也可以使用 :buffers
命令查看被编辑的文件,该命令会在屏幕底部显示一个文件列表,执行 :buffer 缓冲区编号
即可切换到指定的缓冲区(文件)。
我们也可以将更多的文件加入当前的编辑会话中,在 ex 命令:e(编辑,edit 的缩写)的后面跟上文件名就可以打开更多文件 :e filename
将一个文件的内容复制到另一个文件中示例:
先创建两个文件
foo.txt:
ls-output.txt:
继续vi foo.txt ls-output.txt
,将光标一直第一行,输入yy复制该行,使用命令:buffer 2
切换到2号缓冲区:
将光标移至第一行,输入 p 命令,粘贴一个文件中复制的内容:
将整个文件插入另一个文件示例:
首先开启一个新会话,只打开一个文件vi ls-output.txt
:
接着将光标移动至第三行,输入 ex 命令 :r foo.txt
(:r 读取命令绘制光标之下插入指定文件),完成。
除了 ex 命令 :w
,还有其他一些方法保存工作:在命令模式下,输入 ZZ 可以保存当前文件并退出 vi(等同于 :wq
)。另外,:w 命令也可以指定一个可选的文件名,作用类似于“另存为”(例如我们正在编辑 foo.txt,想要将其另存为 foo1.txt,可以这样::w foo1.txt
),不过需要注意的是:虽然该命令会将文件以新名称保存,但并不更改编辑中的原文件名,用户继续编辑的文件还是 foo.txt,而不是 foo1.txt)。
虽说 Shell 提示符(简称提示符)是看似一个微不足道的一个小细节,但是也可以借此揭示一些 Shell 和终端仿真器的内部工作机制。和 Linux 中的很多其他事物一样,提示符也具备很强的可配置性,算得上颇为实用的一件工具了也是。
默认的提示符类似于下面这样,包含了用户名、主机名、当前工作目录:
[me@linuxbox ~]$
提示符是由环境变量 PS1(提示字符串1,prompt string 1 的缩写)定义的,可以使用 echo 命令来查看其 PS1 的内容:
从结果中,我们可以看出 PS1 包含了一些能够在提示符中看到的字符,例如[]、@、$,剩下的则就是反斜线转义字符了,下表中列出了提示符中用到的转义字符:
转义字符 | 显示内容 |
---|---|
\a | ASCII 响铃,会使计算机发出蜂鸣声 |
\d | 当前日期(“星期几-月-日”格式)例如 Mon May 26 |
\h | 本地服务器的主镜明,不包括结尾域名 |
\H | 完整的主机名 |
\j | 执行在当前 Shell 会话中的作业数量 |
\l | 当前终端设备名称 |
\n | 换行符 |
\r | 回车符 |
\s | Shell 程序的名称 |
\t | 24 小时制的当前时间(时:分:秒) |
\T | 12 小时制的当前时间 |
@ | 12 小时制的当前时间(AM/PM) |
\A | 24 小时制的当前时间(时:分) |
\u | 当前用户名 |
\v | Shell 版本号 |
\V | Shell 版本号和发布号 |
\w | 当前工作目录 |
\W | 当前工作目录的最后一部分 |
! | 当前命令的历史记录编号 |
# | 当前 Shell 会话中书如果的命令数量 |
$ | 显示 $,如果拥有超级用户权限的话,则显示 # |
[ | 表明一个或多个非输出字符序列的开头。用于嵌入非输出的控制字符,以某种方式操作终端仿真器,例如移动光标或更改文本颜色 |
] | 表明一个或多个非输出字符序列的结束 |
有了上面那些特殊字符,我们就可以随心所欲的更换提示符了。首先,备份现有的提示符 ps1_old="$PS1"
以便随后恢复 PS1="$ps1_old"
。来看一看如果设置一个空提示会怎样 PS1=
:
如果将提示符设置为空,那么得到的内容也是空,提示符完全消失了!不适感袭来,为此我们将其替换为最小化的提示符 PS1="\$ "
:
这样至少可以看出来自己在做什么哈哈,注意双引号里面是以空格结尾的哦,要不然命令就和提示符连接到一起啦!接着在提示符中添加响铃 PS1="\[\a\]\$ "
,这样一来,在每次显示提示符的时候,应该都能听到蜂鸣声(不过有些系统禁止了这个“特性”)。注意,我们在提示符中加入了 [ 和 ] 转义字符,因为 ASCII 响铃属于非输出字符,也就是说它并不会移动光标,所以我们需要告诉 Bash,以便 Bash 能够正确地确定提示符的长度。
接下来我们尝试在提示符中加入主机名和时间信息 PS1="\A \h \$ "
:
最后我们来制作一个类似于默认提示符的新提示符 PS1="<\u@\h \W>\$ "
:
大多数终端仿真器能够识别某些非输出字符序列,用于控制字符属性(如颜色、粗体及文本闪烁)和光标位置等。其中,字符的颜色是由发送到终端仿真器的 ANSI 转义代码来控制的,转义代码可以嵌入要显示的字符流中,被终端解释为一条命令。[ 和 ] 这两个转义字符用来封装非输出字符。ANSI 转义代码以八进制数 033 开头(改代码由 Esc 键生成),后面跟着一个可选的字符属性,接着是一条命令,例如代码 \033[0;30m
可以将文本设置为普通的(attribute=0)黑色。
下面列出了用于设置文本颜色的转义代码(注意,颜色分为两组,区别在于是否应用了粗体(bold)属性(1),该属性使颜色分为深色和浅色):
转义代码 | 文本颜色 | 转义代码 | 文本颜色 |
---|---|---|---|
\033[0;30m | 黑色 | \033[1;30m | 深灰色 |
\033[0;31m | 红色 | \033[1;31m | 浅红色 |
\033[0;32m | 绿色 | \033[1;32m | 浅绿色 |
\033[0;33m | 棕色 | \033[1;33m | 黄色 |
\033[0;34m | 蓝色 | \033[1;34m | 浅蓝色 |
\033[0;35m | 紫色 | \033[1;35m | 浅紫色 |
\033[0;36m | 青色 | \033[1;36m | 浅青色 |
\033[0;37m | 浅灰色 | \033[1;37m | 白色 |
让我们来执行一个红色的提示符(其印刷效果看起来是灰色的),在提示符开头处插入转移代码 PS1="\[\033[0;31m\]<\u@\h \w>\$ "
:
确实也管用,但是在提示符之后输出的所有文本也都全都变成了红色。为了解决这个问题,我们在提示符结尾处添加另一端转移代码,告知终端仿真器恢复原先的颜色 PS1="\[\033[0;31m\]<\u@\h \w>\$\[\033[0m\] "
:
也可以使用转义代码设置文本背景色(不支持粗体属性):
序列 | 背景色 | 序列 | 背景色 |
---|---|---|---|
\033[0;40m | 黑色 | \033[0;44m | 蓝色 |
\033[0;41m | 红色 | \033[0;45m | 紫色 |
\033[0;42m | 绿色 | \033[0;46m | 青色 |
\033[0;43m | 棕色 | \033[0;47m | 浅灰色 |
所以呢,创建由红色背景的提示符也是很简单的:PS1="\[\033[0;41m\]<\u@\h \w>\$\[\033[0m\] "
恢复提示符:PS1="$ps1_old"
或者 PS1="\[\033[0m\]<\u@\h \w>\$ "
注意:除了普通(0)和粗体(1)字符属性,还可以为文本设置下划线(4)、闪烁(5)及反显(7)(前景色与背景色交换)
转义字符也可以用来移动光标,通常用于在屏幕的不同位置(如每次绘制提示符时,在屏幕上方角落处)显示时钟或其他种类消息,下面是可用于移动光标的转义代码:
转义代码 | 作用 |
---|---|
\033[l;cH | 将光标移动至第一行 c 列 |
\033[nA | 将光标向上移动 n 行 |
\033[nB | 将光标向下移动 n 行 |
\033[nC | 将光标向前移动 n 个字符 |
\033[nD | 将光标向后移动 n 个字符 |
\033[2J | 清空屏幕并将光标移动至左上角(0行0列) |
\033[K | 从光标所在处一直清除到当前行末尾 |
\033[s | 保存光标当前位置 |
\033[u | 恢复先前保存的光标位置 |
利用上表,我们可以创建一个提示符,使得每次出现的时候都会在屏幕顶部绘制出一个内含时钟(黄色数字)红色横条:PS1="\[\033[s\033[0;0H\033[0;41m\033[K\033[1;33m\t\033[0m\033[u\]<\u@\h \W>\$ "
,以下是对其命令各部分转义代码的作用释义:
转义代码 | 作用 |
---|---|
\ [ | 表示非输出字符序列的开始。其目的在于使 Bash 能够正确计算字符串可输出部分的长度。否则的话,命令行编辑特性无法正确定位光标 |
\033[s | 保存光标位置。这是为了能在绘制完屏幕顶部的横条和时钟之后,使光标返回原处(某些终端仿真器可能不识别此代码) |
\033[0;0H | 将光标移至屏幕左上角(0行0列) |
\033[0;41m | 将背景色设置为红色 |
\033[K | 从光标当前所在处(屏幕左上角)一直清除到行尾。因为背景色现在为红色,所以清除后的行就是红色的,,从而创建出了红色横条。注意,清除至行尾并不会改变光标位置,会仍然停留在左上角 |
\033[1;33m | 将文本设置为黄色 |
\t | 显示当前时间。尽管这属于“可输出”元素,但我们仍将其包含着提示符的非输出部分,这是因为我们不想让 Bash 在计算所显示的提示符真实长度时把时钟也纳入其中 |
\033[0m | 关闭颜色,对文本和背景均有效 |
\033[u | 恢复先前保存的光标位置 |
] | 结束非输出字符序列 |
<\u@\h \W>$ | 提示符 |
我们显然不想每次都输入这样一长串代码,所以将其添加到 .bashr 文件是一个一劳永逸的解决办法,为此我们把下列两行加入该文件中:
PS1="\[\033[s\033[0;0H\033[0;41m\033[K\033[1;33m\t\033[0m\033[u\]<\u@\h \W>\$ " export PS1
讲真哦,这个最后的保存提示符不知道为什么一直都没有实现,参考书上确实是 .bashr 文件,但虚拟机上面只有 .bashrc 和 .bash_profile 文件,我三个文件都写入了一遍,但是执行 echo $PS1
后还是系统默认的样式。。。