[Shell]-1-Bash Shell

引言

Shell是运行在Linux系统中的一种程序,它就像系统的外壳,将用户输入的指令通过这个外壳解释并传递给系统内核执行,在Linux系统中,最常用的Shell为Bash Shell,本系列文章也主要围绕Bash Shell来讲解演示。

文章目录

0×1.Bash Shell下常用快捷键

终端开启/关闭快捷键:

					Ctrl+Alt+T 打开新终端窗口;
					Ctrl+Shift+T 在终端窗口中新开标签页;
					Ctrl+Shift+N 新开一个终端窗口(需要在打开终端窗口后);
					Ctrl+Shift+W 关闭当前终端标签页;
					Ctrl+Shift+Q 关闭当前终端窗口;
					

终端操作快捷键:

					F11 终端全屏显示/退出终端全屏;
					Ctrl+Shift+C 复制终端中鼠标选中的文本;
					Ctrl+Shift+V 将复制的内容粘贴到终端中;
					Ctrl+Shift+加号 终端字体放大;
					Ctrl+减号 终端字体缩小;
					Ctrl+0 终端字体恢复默认大小;
					

终端搜索命令:

					Shift+Ctrl+F 打开Find窗口,提供待搜索文本的搜索选项;
					Shift+Ctrl+H 从终端会话的当前位置开始向前搜索指定文本;
					Shift+Ctrl+G 从终端会话的当前位置开始向后搜索指定文本;
					

0×2.理解Bash进程与子进程

查看当前Bash进程与进程树:

					#使用"ps --forest"查看进程树,可以看到输出中,ps命令是bash的子进程
					qing@qingsword.com:~$ ps --forest
					  PID TTY          TIME CMD
					 3315 pts/3    00:00:00 bash
					 5815 pts/3    00:00:00  \_ ps

					 #在当前Bash中执行三次bash命令
					qing@qingsword.com:~$ bash
					qing@qingsword.com:~$ bash
					qing@qingsword.com:~$ bash

					#再次使用"ps --forest"查看进程树,可以看到在父bash进程下面存在三个子bash进程,ps执行在最后那个子bash下面
					qing@qingsword.com:~$ ps --forest
					  PID TTY          TIME CMD
					 3315 pts/3    00:00:00 bash
					 5816 pts/3    00:00:00  \_ bash
					 5824 pts/3    00:00:00      \_ bash
					 5832 pts/3    00:00:00          \_ bash
					 5840 pts/3    00:00:00              \_ ps

					 #通过"ps -f"命令,可以查看到进程"父子"之间的关系,父进程3315(PID)的子进程是5816,以此类推(PPID指向这个进程的父进程PID,表示进程是这个父PID的子进程)
					qing@qingsword.com:~$ ps -f
					UID        PID  PPID  C STIME TTY          TIME CMD
					qing      3315  2442  0 20:45 pts/3    00:00:00 bash
					qing      5816  3315  0 22:12 pts/3    00:00:00 bash
					qing      5824  5816  0 22:12 pts/3    00:00:00 bash
					qing      5832  5824  0 22:12 pts/3    00:00:00 bash
					qing      5841  5832  0 22:12 pts/3    00:00:00 ps -f
					

0×3.命令列表与进程列表

在Bash Shell中,可以使用分号";"逐个执行命令,这样将命令通过";"分隔的一串命令集,就叫做“命令列表”,例如:

					#下面这个"命令列表"包含三条命令,pwd和两个echo,执行结果如下所示
					qing@qingsword.com:~$ pwd;echo www.qingsword.com;echo qingsword
					/home/qing
					www.qingsword.com
					qingsword

					#通过上面实例可以看到,"命令列表"是从左往右依次执行的,那么如果"命令列表"中包含错误不存在的命令,接下来的命令还会继续执行吗?下面的实例验证了如果不小心输入了一个不存在的命令,Bash会在执行到这个"命令列表"中这条指令的时候报错,并且会继续执行接下来的命令
					qing@qingsword.com:~$ pwd;echo www.qingsword.com;echo qingsword;ssxs;echo qing
					/home/qing
					www.qingsword.com
					qingsword
					Command 'ssxs' not found, #执行'ssxs'命令报错
					qing #接下来的命令正常执行
					

在Bash Shell中,可以使用小括号"()"来包含一条或多条命令,被包含在小括号中的命令会被Bash创建一个子Bash来执行,这样在一条指令中包含多个"()"创建的命令集,就叫做“进程列表”,例如:

					#pwd命令在最外层Bash中执行,然后这个父Bash会创建一个子Bash,执行echo www.qingsword.com命令,紧接着的ps --forest命令能够让我们更加清晰的看到ps命令执行在一个子Bash进程下,然后这个子Bash会再创建一个子Bash,执行echo qingsword命令,通过ps --forest命令命令能够很清楚的看到创建的第二个子Bash,“进程列表”的执行也是从左往右,遇到命令执行错误继续执行下一条命令
					qing@qingsword.com:~$ pwd;(echo www.qingsword.com;ps --forest;(echo qingsword;ps --forest))
					/home/qing
					www.qingsword.com
					  PID TTY          TIME CMD
					 3152 pts/6    00:00:00 bash
					 6006 pts/6    00:00:00  \_ bash
					 6007 pts/6    00:00:00      \_ ps
					qingsword
					  PID TTY          TIME CMD
					 3152 pts/6    00:00:00 bash
					 6006 pts/6    00:00:00  \_ bash
					 6008 pts/6    00:00:00      \_ bash
					 6009 pts/6    00:00:00          \_ ps
					

通过上面这个实例不难看出,Bash执行命令时遇到“小括号”就会创建一个子Bash来执行小括号中的命令。

在Bash Shell中有一个系统全局变量"$BASH_SUBSHELL",我们可以通过输出这个变量的值,来判断当前输出这个值的Bash是否为一个子Bash,例如:

					#没有创建子Bash,输出0
					qing@qingsword.com:~$ pwd;echo www.qingsword.com;echo $BASH_SUBSHELL
					/home/qing
					www.qingsword.com
					0

					#创建了两个子Bash,输出2
					qing@qingsword.com:~$ (pwd;echo www.qingsword.com;(echo qingsword;echo $BASH_SUBSHELL))
					/home/qing
					www.qingsword.com
					qingsword
					2

					#创建了三个子Bash,输出3
					qing@qingsword.com:~$ (pwd;echo www.qingsword.com;(echo qingsword;(echo $BASH_SUBSHELL)))
					/home/qing
					www.qingsword.com
					qingsword
					3
					
					#那么下面的这种写法为什么输出的是1?Bash不应该创建了两个子Bash吗?这是因为$BASH_SUBSHELL输出的位置是在第一个括号中,此时父Bash才创建了第一个子Bash,这个被创建的Bash执行了这条echo指令,所以输出的是1
					qing@qingsword.com:~$ pwd;(echo www.qingsword.com;echo $BASH_SUBSHELL;(echo qingsword))
					/home/qing
					www.qingsword.com
					1
					qingsword
					

0×4.协程与后台执行

“协程”的作用与小括号相同,都是在当前Bash中创建一个子进程,并执行我们输入的命令,“协程”的创建是通过coproc命令实现的,例如:

					#创建一个“协程”,将创建的子进程在后台休眠20秒然后退出
					qing@qingsword.com:~$ coproc sleep 20
					[1] 6400 #创建的子Bash进程号

					#通过“ps --forest”命令能够清晰的看到,当前Bash下创建了一个子sleep进程
					qing@qingsword.com:~$ ps --forest
					  PID TTY          TIME CMD
					 3152 pts/6    00:00:00 bash
					 6400 pts/6    00:00:00  \_ sleep
					 6401 pts/6    00:00:00  \_ ps

					#实际上协程命令与在命令后添加一个符号"&"效果相同
					qing@qingsword.com:~$ sleep 20 &
					[1] 3993
					qing@qingsword.com:~$ jobs
					[1]+  运行中               sleep 20 &
					qing@qingsword.com:~$ ps --forest
					  PID TTY          TIME CMD
					 2942 pts/8    00:00:00 bash
					 3993 pts/8    00:00:00  \_ sleep
					 3996 pts/8    00:00:00  \_ ps
					qing@qingsword.com:~$ coproc sleep 20
					[2] 4129
					qing@qingsword.com:~$ jobs
					[1]-  已完成               sleep 20
					[2]+  运行中               coproc COPROC sleep 20 &
					

0×5.外部命令与内建命令

外部命令,也被称为文件系统命令,是存在于Bash Shell之外的程序;它们并不是Bash Shell程序的一部分;外部命令程序通常位于/bin、/usr/bin、/sbin或/usr/sbin中;当外部命令执行时,会创建出一个子进程,这种操作被称为衍生(forking)。

ps就是一个外部命令,当它执行时,会在当前Bash下创建一个子进程,例如:

					qing@qingsword.com:~$ ps --forest
					  PID TTY          TIME CMD
					 2942 pts/8    00:00:00 bash
					 5447 pts/8    00:00:00  \_ ps
					

可以通过“type -a”命令来判断一个命令是外部命令还是内建命令,例如:

					#cd命令就是Bash的内建命令,也就是Bash Shell集成的命令中的一个,不需要调用外部程序就能执行
					qing@qingsword.com:~$ type -a cd
					cd 是 shell 内建

					#ps和find命令为外部命令
					qing@qingsword.com:~$ type -a ps
					ps 是 /bin/ps
					qing@qingsword.com:~$ type -a find
					find 是 /usr/bin/find

					#echo和pwd这两个命令既是内建命令,也有外部命令,两者实现的方式不同,但执行效果相同,我们既能够使用它们的内建命令,也能够调用它们的外部命令
					qing@qingsword.com:~$ type -a echo
					echo 是 shell 内建
					echo 是 /bin/echo
					
					qing@qingsword.com:~$ type -a pwd
					pwd 是 shell 内建
					pwd 是 /bin/pwd
					

0×6.历史命令与别名

关于历史输入命令列表,可以使用history来显示已经输入过的命令列表,这个列表保存在当前用户家目录的“.bash_history”文件中,当我们使用cat查看此文件时,看到的命令列表可能不会存在我们新输入的命令,这是因为Bash输入的命令有一个时间缓存,可以使用history -a命令强制将当前Bash缓存输入到“.bash_history”文件中,如果向清空历史输入命令,直接清空这个文件内容即可,例如:

					qing@qingsword.com:~$ history
					..... 省略部分输出
					 2012  type -a cd
					 2013  type -a ls
					 2014  type -a echo
					 2015  type -a find
					 2016  type -a pwd
					 2017  type -a ps
					 2018  history 
					 2019  cat .bash_history 
					 2020  history 
					

Alias 命令是Bash Shell的内建命令,它允许你为常用的命令(及其参数)创建另一个名称,从而将输入量减少到最低,例如:

					#定义一个临时(当前Bash中有效,Bash关闭就清除)命令别名"osupdate",只要执行"osupdate"就相当于执行后面的系统升级命令,等号后面的命令放在一对单引号中
					qing@qingsword.com:~$ alias osupdate='sudo apt update && sudo apt upgrade'
					

如果想在Bash执行时就加载我们指定的别名,可以将上面这段命令写到用户家目录的".bashrc"文件的末尾,这样每次启动Bash Shell,系统就会自动加载这个别名。