[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,系统就会自动加载这个别名。