GUN/Bash 系列(八)快捷键总结
下面总结的是 GNU/Bash 中部分最实用的命令名称及默认情况下它们关联的快捷键。更多快捷键请参考 GNU/Bash 文档的 Readline 库。
下面总结的是 GNU/Bash 中部分最实用的命令名称及默认情况下它们关联的快捷键。更多快捷键请参考 GNU/Bash 文档的 Readline 库。
搭好博客后,在权威域名服务商 GoDaddy 注册了一个新域名使用。当配置无 www 前缀域名时,却遇到了一些配置问题。
Q1 参加了一场 Docker 技术分享后,发现了 Docker 这个好东西,回头动手安装,打算跑起来体验一番,却遇到了一些蛋疼的问题。
在使用交互式 Bash 时,一个配置得当的命令提示符可以为用户带来不少便利,本文讲解如何配置命令提示符。
命令提示符涉及到以下两个环境变量:
环境变量 | 描述 |
---|---|
PS1 |
主提示符,Bash 会在准备好读入一条命令时显示,默认值 \s-\v\$ |
PS2 |
次提示符,Bash 会在需要更多的输入来完成一条命令时显示,默认值 > |
Bash 允许通过插入一些反斜杠转义的特殊字符来定制这些提示符,常用的转义字符如下:
转义字符 | 描述 |
---|---|
\h |
主机名,第一个 . 之前的部分 |
\H |
主机名 |
\j |
shell 当前管理的作业数量 |
\l |
shell 的终端设备名的基本部分 |
\n |
新行符 |
\r |
回车 |
\s |
shell 的名称, $0 的基本部分 (最后一个斜杠后面的部分) |
\u |
当前用户的用户名 |
\v |
bash 的版本 (例如,4.3) |
\w |
当前工作目录 |
\W |
当前工作目录的基本部分 |
\! |
此命令的历史编号 |
\# |
此命令的命令编号 |
\$ |
如果有效 UID 为 0,则显示 # , 否则 $ |
\\ |
一个反斜杠 |
除此之外,还有一些不太常用的日期转义字符:
转义字符 | 描述 |
---|---|
\d |
当前日期,格式是 “星期 月份 日” (例如,”Tue May 26”) |
\D{format} |
自定义日期格式,花括号是必需的 |
\t |
当前时间,采用 24 小时制的 HH:MM:SS 格式 |
\T |
当前时间,采用 12 小时制的 HH:MM:SS 格式 |
\@ |
当前时间,采用 12 小时制上午/下午 am/pm 格式 |
\A |
当前时间,采用 24 小时制上午/下午格式 |
由于 PS1
默认设置的 \s-\v\$
实在是太废毫无信息量可言,显示如下:
1 | bash-4.3$ |
因此可以通过修改 ~/.bash_profile
文件来定制自己的命令提示符。例如,使用 CentOS 默认设置的 [\u@\h \W]\$
:
1 | $ vim ~/.bash_profile |
定制后,能够知道当前用户、主机名、工作目录:
1 | [root@BGP-BJ-C-5HL ~]$ |
http://www.gnu.org/software/bash/manual/bashref.html#Controlling-the-Prompt
命令行的扩展是在拆分成词之后进行的。共有七种类型的扩展:
常用的四种如下
用于偷懒,例如:
1 | x{a,b,cd}y |
扩展为:
1 | xay xby xcdy |
再例如:
1 | mkdir /usr/local/src/bash/{old,new,dist} |
扩展为:
1 | mkdir /usr/local/src/bash/old |
1 | ${parameter} |
1 | $(( expression )) |
命令替换允许命令的输出替换命令本身。当命令被以下特殊字符包括时,将发生命令替换:
1 | $(command) |
或
1 | `command` |
https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Shell-Expansions
GUN/Bash 提供了一些内建命令 (BUILTIN COMMANDS),用于在命令行上方便使用:
echo
显示一行文本或变量
unset
取消变量
set
查看所有变量(环境变量&用户变量)
env
查看所有环境变量(格式好看些)
export
export
命令将局部变量转为环境变量,但是用户注销时值将丢失;export
命令,相当于每次登录时系统都帮用户 export
一下所需环境变量;source
或 .
exit
注销)declare
或 typeset
-a
定义数组类型-i
定义整数类型-x
将用户变量转成环境变量(与 export
一样)+x
将环境变量降为用户变量-r
定义 readonly 类型read
读取来自键盘输入的变量
-p
后接提示符-t
后接等待“秒数”test
-e
该文件名是否存在(exist)-s
该文件大小是否非 0-z
是否为空字符串(zero)-f
是否为文件(file)-d
是否为目录(directory)-b
是否为块特殊文件(block)-L
是否为连接文件(link)-r
-w
-x
是否可读、可写、可执行-a
-o
!
且、或、非-eq
-ne
-gt
-lt
-ge
-le
(判断2个整数)相等、不等、大于、小于、大于等于、小于等于[]
[]
的使用方法与 test
命令几乎一模一样,只是中括号常用于条件判断式 if…then…fi
''
或双引号 ""
括起来sh
以 sh
方式执行,至少需要 r
权限;若以绝对路径方式执行,则需要 r
与 x
权限
-n
不执行 script,仅验证语法。若语法无误,则不显示任何信息。(貌似仅能验证关键字错误?)-v
在执行 script 前,先将 script 的内容输出到屏幕上-x
将 script 执行过程逐步输出到屏幕上Bash 是一个多任务的 CLI ,有以下作业控制(Job Control)相关的命令:
命令 | 描述 |
---|---|
jobs |
显示(当前会话中的)后台作业表 |
fg |
将后台作业调到前台执行(前台运行作业) |
bg |
继续执行指定的后台作业(后台运行作业) |
Ctrl+Z |
暂停/挂起目前的命令,转入后台运行。通过在命令后追加一个&,可以将该命令转入后台运行 |
Ctrl+C |
终止目前的命令 |
http://www.gnu.org/software/bash/manual/bashref.html#Shell-Builtin-Commands
即单个命令。
pipeline(管道)是一个或多个命令的序列,用字符 | 分隔。管道的命令格式如下:
1 | command [ | command2 ... ] |
管道的特点如下:
|
管道的处理流程如下图:
文件描述符 | 名称 | 描述 |
---|---|---|
0 |
stdin |
标准输入(Standard input) |
1 |
stdout |
标准输出(Standard output) |
2 |
stderr |
标准错误输出(Standard error) |
操作符 | 描述 |
---|---|
< |
重定向输入(Redirecting Input) |
> |
重定向输出(Redirecting Output),与 1> 等价 |
>> |
追加到重定向输出(Appending Redirected Output) |
2> |
重定向错误输出(Redirecting Error) |
2>> |
追加到重定向错误输出(Appending Redirected Error) |
&> |
重定向标准输出和标准错误输出(Redirecting Standard Output and Standard Error)。 推荐使用,它与 >word 2>&1 在语义上等价 |
>& |
同上,但不推荐使用 |
2>&1 |
将标准错误输出重定向到标准输出 |
在命令执行前,它的输入和输出可能被 redirected (重定向),该功能可以用于如下场景:
2> /dev/null
将它丢掉;/etc/crontab
)的运行结果,需要存下来时;例子:
快速创建带内容的文件:
1 | $ echo "hello world" > /tmp/file |
将 stdout
和 stderr
都重定向到本地日志文件:
1 | java -jar app.jar >/tmp/stdout.log 2>&1 |
将 stdout
和 stderr
都丢弃(等价操作):
1 | java -jar app.jar >/dev/null 2>&1 |
list(序列)是一个或多个管道,用操作符 ;
、&
、&&
、||
分隔的序列, 并且可以选择用 ;
、&
、<newline>
新行符结束。
操作符 | 例子 | 描述 |
---|---|---|
&& |
command1 && command2 | 一个 AND 序列。command2 只有在 command1 返回 0 时才被执行 |
|| |
command1 || command2 | 一个 OR 序列。command2 只有在 command1 返回非 0 状态时才被执行 |
; |
command1; command2 | 结束一个序列。不考虑命令的退出状态,连续执行命令 |
<newline> |
command<newline> | 结束一个序列 |
& |
command1 & | 如果一个命令是由 & 结束的, shell 将在后台的子 shell 中执行这个命令 |
&&
和 ||
优先级相同, ;
和 &
优先级相同。在某些情况下,很多命令我想要一次输入去运行,有两种方法:
例如,一串无人值守源代码形式安装的命令如下:
1 | $ ./configure && make && make install |
compound command(复合命令)是如下情况之一:
(list)
{ list; }
((expression))
[[ expression ]]
if list; then list; [ elif list; then list; ] ... [ else list; ] fi
select name [ in word ] ; do list ; done
case word in [ [(] pattern [ | pattern ]
select in 通常和 case in 一起使用,在用户输入不同的编号时可以做出不同的反应,见:https://blog.csdn.net/yrx420909/article/details/104308041
while list; do list; done
until list; do list; done
for name [ in word ] ; do list ; done
1 | #!/bin/bash |
for (( expr1 ; expr2 ; expr3 )) ; do list ; done
https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Arrays
https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Shell-Commands
引用用于:
三种引用机制:
引用符 | 描述 |
---|---|
转义字符 \ |
保留其后下一个字符的字面意义 |
单引号 '' |
保留引用中所有字符的字面意义 |
双引号 "" |
保留引用中所有字符的字面意义,例外的情况是 $, `, 和 \ |
单引号与双引号的使用区别:
注意,反引号 `
与单引号 ''
和双引号 ""
作用不同,是用于命令替换(Command Substitution),详见《Shell 常用扩展总结》。
以 #
起始的词使得这个词和所有同一行上所有剩余的字符都被忽略。
参数(Parameter)是存储值的实体。它可以是以下三类:
变量,即用名称(name)表示的参数,其具有值(value)以及零或多个属性(attributes)。
通过 $name
引用,在双引号 ""
中可以被引用。
通过以下语句为变量赋值:name=[value]
。如果变量未赋值,默认值为 null
字符串。
通过内建命令 unset
为取消变量。
通过内建命令 declare
为变量分配属性(attributes)。
所有值都接受以下扩展:
$n
:$1
表示第一个参数,$2
表示第二个参数,以此类推。
$0
:表示脚本文件名
$#
:表示命令行参数的个数
$?
:前一个命令或函数的返回码,0
为成功,非 0
为错误/失败
$*
:以”参数1 参数2 … “ 的形式保存所有参数
$@
:以”参数1” “参数2” … 的形式保存所有参数
$$
:本程序的 PID(进程 ID 号)
$!
:最近执行的后台(即异步)命令的 PID
https://www.gnu.org/software/bash/manual/html_node/Quoting.html
https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Shell-Parameters
了解完什么是 Shell,有哪些 Shell 类型之后,本文开始主要关注 Bash Shell。
/etc/passwd
文件,在这个文件里包含了用户名、密码和该用户的登录 shell,如 /bin/bash 。 /bin/login 在子进程里用 execve
调用了 /bin/bash 。echo
命令时,我们一般不会输入 /bin/echo
,而仅仅是输入 echo
。那为什么这样 bash 也能够找到 /bin/echo 呢?原因是 Linux 操作系统支持这样一种策略:shell 的一个环境变量 PATH 里头存放了程序的一些路径,当 shell 执行程序时会去这些目录下查找。which
作为 shell(这里特指 bash )的一个内置命令,如果用户输入的命令是磁盘上的某个程序,它会返回这个文件的全路径。Bash 如何执行它的启动文件?交互式 shell(interactive shell)下需要区分两种情况:
在下列情况下,我们可以获得一个 login shell:
ssh
登录。这种情况下获得的 login shell 是一个交互式 shell。--login
选项调用 bash,可以获得一个交互式 login shell。--login
选项调用 bash(比如在 shell 脚本第一行做如下指定:#!/bin/bash --login
),此时得到一个非交互式的 login shell。su -
切换到指定用户时,获得此用户的 login shell。如果不使用 -
,则获得 non-login shell。login shell 与 non-login shell 的主要区别在于它们启动时会读取不同的配置文件,从而导致环境不一样。login shell 启动时:
首先读取全局配置:/etc/profile
然后依次查找以下三个文件,读取第一个找到且可读的文件:
~/.bash_profile
~/.bash_login
~/.profile
退出时,读取:~/.bash_logout
交互式的 non-login shell 启动时,会读取:
~/.bashrc
通常我们要定制一些配置时(例如 alias 别名),会将配置写在 ~/.bashrc
中,然后在 ~/.bash_profile
中读取 ~/.bashrc
,这样可以保证 login shell 和 non-login shell 得到相同的配置:
1 | test -f ~/.bashrc && . ~/.bashrc |
至于 /etc/profile
就不要轻易去改啦,毕竟会影响系统全局的配置。
当 Bash 以非交互的方式(non-interactive shell)启动时,例如在运行一个 shell 脚本时,它会查找环境变量 BASH_ENV
,如果存在则将它的值展开,使用展开的值作为一个文件的名称,读取并执行。 Bash 运作的过程就如同执行了下列命令:
1 | if [ -n "$BASH_ENV" ]; then |
其它情况:
Aliases are not expanded when the shell is not interactive.
Functions are executed in the context of the current shell; no new process is created to interpret them (contrast this with the execution of a shell script).