当登陆Linux系统时,会为用户分配一个shell。如果在/etc/passwd中该用户配置的shell为 /bin/bash ,那么就为用户分配一个bash shell,当登陆用户的身份审核通过后,就会加载bash进程,bash进程再加载它的各个配置文件(/etc/profile、/etc/profile.d/*.sh、~/.bashrc等),从而配置好bash的执行环境。 bash内置命令和普通的命令都能在bash环境下执行,并实现它们对应的功能。但它们却有很大区别,最典型的一个区别是ps等工具能捕捉到普通命令的进程,却捕捉不到bash内置命令的进程。 Shell脚本中命令运行时若不用创建子进程则是内置命令;—shell把它们当成脚本中的函数处理; 内置命令在目录列表时是看不见的,它们由Shell本身提供。 内置命令由shell程序识别并在shell程序内部完成运行,通常在linux系统加载运行时shell就被加载并驻留在系统内存中。内部命令是写在bashy源码里面的,其执行速度比外部命令快,因为解析内部命令shell不需要创建子进程 | |
bash内置命令和普通命令不一样。普通命令可以直接执行,不依赖于某种执行环境。例如,sleep命令,可以直接以pid=1的init/systemd为父进程而执行。那些daemon类的服务进程更是如此,它们不依赖于终端,也不依赖于执行环境,只要给它们配置好,就可以直接找init/systemd当爹。 而bash内置命令,既然称之为"bash内置命令",顾名思义是bash内置的。当我们在当前bash环境下执行bash内置命令,经过shell的一轮解析之后,发现这是个bash内置命令,于是直接在当前bash进程的内部调用执行它们。所以bash内置命令自身是没有进程的。 bash内置命令的执行是由bash带着它们执行的。这些bash内置命令无论什么时候执行都必须先找bash为它们提供执行环境 如果是在当前shell中放进后台,则这个爹是新生成的bash进程。这个新的bash进程只负责一件事,就是负责这个后台,为它的孩子们提供它们依赖的bash环境。 | |
作业是指"能选择性地停止、暂停、继续运行某个进程的能力",通俗地说就是作业用来控制谁可以获得终端(前台进程)、谁不能获得终端(后台进程)。 当一个进程的进程组号和当前终端的进程组号相同,则这个进程是前台进程,受键盘影响,可以读、写终端。当一个进程的进程组号和当前终端的进程组号不同时,则这个进程是后台进程,它们不受键盘影响,读、写终端时需要发送特定的信号。 后台任务依赖于当前所在的终端,因为它可能会恢复到前台去运行。但当前终端往往会和一个bash进程关联绑定,该bash进程具有当前终端的控制权。当一个进程是前台进程时,它是在当前bash进程下执行的,此时该bash进程失去控制权,也就是被阻塞。当进程进入后台,意味着它会离开当前bash环境,进入后台执行环境,因为只有离开当前bash环境,才能立刻将终端的控制权还给当前bash进程。 bash内置命令要放入后台,放入后台意味着它要离开当前bash环境,所以它在进入后台开始执行前,必须新找一个bash爹为它提供执行环境,所以它新生成了一个bash进程。其实这个新的bash和当前bash进程是不一样的,这个新bash是非交互式的shell,可以直接使用 杀掉终端进程和杀掉当前bash进程对后台任务的影响不一样:杀掉当前bash进程后,后台任务会挂在init/systemd下,而杀掉终端后,后台任务也会中止。后台任务依赖于当前所在的终端。但当前终端往往会和一个bash进程关联绑定,该bash进程具有当前终端的控制权,所以杀掉终端进程和杀掉当前所在bash进程都能结束一个终端。 杀掉终端进程时,终端进程会给自己进程组内的所有进程包括bash进程发送一个SIGHUP信号,正是因为收到这个信号,进程组内的所有进程才会中止。
| |
如何让后台进程不依赖于终端: 1.将后台任务放入子shell。 因为将后台任务放入子sh(脚本或者()),当子shell结束后,其内后台任务会立即挂到init/systemd下,这样就脱离了终端。 2.利用bash内置命令disown将任务移出后台或设置为忽略SIGHUP信号 当进程disown移出后台后,虽然暂时还挂在bash进程下,但结束终端进程时,该进程将挂到init/systemd下。所以,这样做也将脱离终端。或者, | |
bash内置命令:bash, :, ., [, alias, bg, bind, break, builtin, caller, cd, command, compgen, complete, compopt, continue, declare, dirs, disown, echo, enable, eval, exec, exit, export, false, fc, fg, getopts, hash, help, history, jobs, kill, let, local, logout, mapfile, popd, printf, pushd, pwd, read, readonly, return, set, shift, shopt, source, suspend, test, times, trap, true, type, typeset, ulimit, umask, unalias, unset, wait】 保留关键字:! case do done elif else esac fi for function if in select then until while { } time [[ ]] | |
. | 使Shell读入指定的Shell程序文件并依次执行文件中的所有语句 |
: | 空,永远返回为空 |
break | 退出f |
bg | 把作业放到后台 |
bind | 显示当前的套接字与函数的绑定情况 |
cd | 切换目录 |
continue | 执行循环的下一步 |
dirs | 显示当前记录的目录 |
echo | 反馈信息到标准输出 |
enable | 启用或者禁用shell内置命令 |
exec | 当Shell执行到exec语句时,不会去创建新的子进程,而是转去执行指定的命令,当指定的命令执行完时,该进程(也就 是 最初的Shell)就终止了,所以Shell程序中exec后面的语句将不再被执行 |
exit | 退出Shell程序。在exit之后可有选择地指定一个数位作为返回状态 |
export | Shell可以用export把它的变量向下带入子Shell,从而让子进程继承父进程 中的环境变量。但子Shell不能用export把 它 的变量向上带入父Shell |
env | 显示或者设置用户变量 |
eval | 读取参数,执行结果命令 |
help | 显示所有内置命令列表,或者显示一个具体命令的用法 |
history | 查看以往使用的所有命令 |
kill | 想由PID 号或作业号指定的进程发送信号,输入kill -l信号列表 |
pwd | 当前目录 |
printf | 显格式字符串,格式:printf "格式字符串" 参数 |
read | 从标准输入读取一行文本 |
readonly | 将一个用户定义的Shell变量标识为不可变。不带任何参数的readonly命令将显示出所有只读的变量 |
return | 返回函数值 |
set | 用于显示或者清除shell环境变量;set、env、export设置的变量均可用unset来清除; |
shift | 语句按如下方式重新命名所有的位置参数变量,即2成为2成为1,3成为3成为2…在程序中每使用一次shift语句,都使所有的位置参数依次向左移动一个位置,并使位置参数$#减1,直到减到0为止 |
test | 条件测试 |
times | 显示用户脚本或任何系统命令的运行时间,第一行给出shell消耗时间 第二行给出运行命令消耗的时间 |
trap | 当前捕获信号时运行指定命令 ulimit 显示或者设置shell资源 |
suspend | 终止当前shell的运行 |
wait | 使Shell等待在后台启动的所有子进程结束。wait的返回值总是真 |
ulimit | 显示或者设置进程可用资源的最大限额 |
unalias | 取消所有的命名别名设置 |
注: 1.在命令前输入command即可以禁止shell函数查找 即command cd 目录 2.在命令前输入builtin,可以强制bash使用内部命令 即builtin echo -n "builtin command echo" # 使用内置命令echo 3.使用外部命令的全路径就可以使用外部命令 即/bin/echo hi 4.使用enable -n将某个/某几个内置bash命令无效化 enable的影响将一直持续到用户退出shell为止 即 enable -n ls 使ls内置无效 enable ls ch重新启动ls enable -a列出所有命令状态 |