Linux 命令行与 shell 脚本编程大全 5 理解 shell

了解子 shell 和 父 shell 之间的关系以及一些命令

5.1 shell 的类型

  1. Linux 中,用户使用的 shell 类型,被配置在 /etc/passwd 文件中,通常都是 bash shell
  2. 除了 bash shell ,CentOS 中一般还内置了 tcsh shelldash shellash shelltcsh shell
  3. 查看当前系统是否内置了上述 shell 类型,可以通过如下方式
    • 可以看到,在下图的 CentOS 环境中,只存在 bash shelldash shell
  4. 但在 macOS 环境中,除了 ash shell 没有内置,其他的几种类型都可以找到

5.1.1 默认的系统 shell

  1. 在用户配置文件与用户绑定的 shell 会在系统启动时运行
  2. 但除了启动用户 shell 之外,还会启动一个系统 shell ,通常被指定为 /bin/sh ,如下图
    • 但是可以看到,/bin/sh 只是 bash shell 的软链接
    • 不过不是所有的系统的默认系统 shell 都指向 bash shell ,Ubuntu 通常会指向 dash shell

5.2 shell 的父子关系

  1. 父 shell 是指用于登录系统的默认 shell
  2. 子 shell 则是在 父 shell 环境中创建的其他 shell
  3. 使用 bash 命令可以在 父 shell 中创建 子 shell ,如下图
    • ps -f 命令第一次执行时,只能获取两条进程信息,-bash 则是当前的 父 shell
    • 在执行 bash 命令后,再次执行 ps -f 命令则获取到了三条进程信息,bash 则是刚才通过执行 bash 命令创建的 子 shell
    • bash 进程的 PPID 和 -bash 进程的 PID 一致,说明后者是前者的父级
  4. bash 命令提供了一些指令,如下图
  5. 使用 exit 退出当前 shell ,如下图
    • 使用 bash 创建一个 子 shell
    • 执行 exit ,再次执行 ps -f ,之前创建的 子 shell 进程就不存在了
  6. 子 shell 并不是真正的多进程处理,层级过多的 子 shell 会带来更多的系统花销,拖慢处理速度

5.2.1 进程列表

  1. 在介绍 进程列表 之前,需要先了解 命令列表
  2. 命令列表 是在多个命令之间通过分号分隔,让一行中的命令可以依次执行,如下图
    • 可以看到,命令被依次执行并输出了结果
  3. 命令列表 想要进化成 进程列表 ,只需要在这些命令两侧加上括号即可,如下图

5.2.1.1 命令列表和进程列表的区别

  1. 那么你可能会问,只是加了括号,但输出结果一致,这两个列表的区别在哪
  2. 区别在于:命令列表 是直接执行这些命令串
  3. 进程列表 会创建一个 子 shell 开执行这些命令,执行完毕后 子 shell 也会随之结束
  4. 使用 echo $BASH_SUBSHELL 命令可以更清晰的知道命令在执行时,是否存在 子 shell ,如下图
    • 如果不存在,会返回 0 ,否则就是存在
    • 返回数字的表达意思是 进程列表 的嵌套层级

5.2.2 别出心裁的子 shell 用法

5.2.2.1 & 命令探索后台模式

  1. 在后台模式中执行命令可以在处理命令的同时让出 CLI ,以供他用
  2. 在待执行命令的末尾添加字符 & ,可以让该命令在后台执行,如下图
    • sleep 5 命令表示当前线程会等待 5 秒,如果直接执行,当前命令行会在 5 秒后才能继续接收输入
    • sleep 5 & 命令执行后则会立即返回一个后台任务 ID ,以及该进程的 PID ,当前命令行也可以立即接收新的输入
    • 需要注意的是 macOS 在命令执行完毕后,会自动输出执行结果,如下图
    • 但 CentOS 不会自动输出执行结果,需要再次执行 jobs 命令,才可以看到执行结果

5.2.2.2 jobs 命令查看后台进程

  1. 使用 jobs 命令可以显示当前运行在后台模式中的所有用户的进程信息
  2. 使用 jobs -l 则可以更详细的显示进程信息,如下图
    • jobs 命令会显示后台进程的任务 ID 、PID 、进程状态、进程命令
    • 同时当后台进程执行完毕后,也就无法通过 jobs 查看对应进程信息

5.2.2.3 将进程列表置入后台

  1. 进程列表 置入后台运行的好处在于:既可以在子 shell 中执行复杂的处理工作,又不会占用当前的 shell 窗口 ,如下图

5.2.2.4 coproc 命令实现协程

  1. 协程 是指在后台生成一个 子 shell ,并在这个 子 shell 中执行命令
  2. 使用 coproc 命令可以实现协程,如下图
    • 可以看到,使用 jobs 命令查看到的进程命令名称最后有一个 & 符号,说明这也是一个后台进程
  3. 上图中大写的 COPROC 是在使用 coproc 命令时指定的默认协程名称
  4. 这个名称是可以自定义的,如下图
    • 完整的语法是 coproc coprocName { command; }
    • 命令中的花括号、空格、分号缺一不可,语法格式非常严格

5.3 理解 shell 的内建命令

5.3.1 外部命令

  1. Linux 中存在 内建命令外部命令 ,可以先理解一下 外部命令
  2. 外部命令 也被称为 文件系统命令 ,不是 shell 程序的一部分
  3. 外部命令 通常被放置在 /bin/usr/bin/sbin/usr/sbin
  4. 外部命令 在执行时,会创建一个子进程,在子进程中执行该命令,这个行为被称为 衍生( Forking )

5.3.1.1 which 命令和 type 命令查看命令归属

  1. 使用 which 命令和 type 命令可以查看指定命令是属于 外部命令 ,还是 内建命令 ,如下图
    • ps 命令位于 /bin 中,说明 ps 命令就是 外部命令

5.3.2 内建命令

  1. 内建命令外部命令 的区别在于,内建命令 不需要使用子进程来执行命令
  2. 内建命令 和 shell 是一体的,作为 shell 工具的组成部分而存在
  3. 内建命令 因为不需要通过衍生行为来执行,所以执行速度会更快、效率更高
  4. 使用 which 命令和 type 命令也可以查看该命令是否属于 内建命令 ,如下图
    • 可以看到,cd exit pwd 命令都属于 内建命令

5.3.2.1 type -a 命令查看命令的多种实现

  1. 有些命令存在多种实现,使用 type -a 可以将该命令的全部实现列举出来,如下图
    • 可以看到,pwd echo 命令既是 内建命令 ,也在 /bin 目录中有一份实现

5.3.2.2 history 命令查看使用过的历史命令

  1. 首先 history 命令是一个 内建命令
  2. 可以通过 history 命令查看之前使用过的命令,如下图
    • 在 CentOS 中,history 命令默认最多可以存储 1000 条历史命令,但这个值可以通过 HISTSIZE 的环境变量进行修改
    • 下图中只列出了 6 条数据,是因为为了方便显示,使用 history -c 命令删除了之前的所有历史数据

5.3.2.3 !! 命令直接执行最近一条历史命令

  1. 使用 !! 命令可以直接在新的一行显示出上一条刚刚执行过的命令,如下图
    • !! 命令执行之后,在下一行出现的 pwd 命令不是手动输入的,而是由 !! 命令呼出的
    • 呼出的命名不会直接执行,只是显示出来,需要手动按回车键,才能再次执行该命令

5.3.2.4 在 .bash_history 文件中查看命令历史记录

  1. 使用 history 命令查看的命令历史记录,被存放在根目录的 .bash_history 文件中
  2. 需要注意的是,命令的历史记录并不是直接存放到该文件,而是先存放到内存中,当 shell 退出时,才被写入到该文件
  3. 想要强制将命令历史记录写入文件中,可以使用 history -a 命令

5.3.2.5 alias 命令实现为命令指定别名

  1. alias 命令也是一个 内建命令
  2. 需要注意的是,直接使用命令创建的别名,只能在当前会话生效,无法做到全局生效
    • 想要全局生效,则需要将别名写入配置文件中,后续章节会有介绍
  3. 使用 alias 命令可以为某个复杂的命令指定一个简单的别名,从而将调用命令的输入减少到最低,如下图
    • 可以看到,通过 alias 命令将 ls -al 命令指向 ll 命令
    • 之后再输出 ll 命令,就可以得到和 ls -al 命令一样的结果

5.3.2.6 alias -p 命令查看当前有多少命令别名

  1. 使用 alias -p 命令可以列出当前系统中存在哪些命令别名可以使用,如下图
  2. 上图是 CentOS 的效果,如果是 macOS ,无法使用 alias -p 命令,直接使用 alias 命令,不加任何后缀即可

5.4 小结

  1. shell 之间存在父子级关系
  2. 使用 bash 命令可以创建 子 shell
  3. 使用 exit 命令可以退出 子 shell
  4. 使用 & 命令可以将命令置入后台
  5. 使用 coproc 命令可以在子进程中执行命令
  6. 命令列表 是指在多个命令之间添加分号,可以依次执行命令
  7. 进程列表 是指在 命令列表 外部添加一对括号,可以将这些命令在子进程中执行
  8. 使用 history 命令可以查看命令历史记录
  9. 使用 !! 命令可以快速呼出最近依次的命令历史记录
  10. 使用 alias 命令可以给长命令指定短别名
发布了418 篇原创文章 · 获赞 47 · 访问量 20万+

猜你喜欢

转载自blog.csdn.net/asing1elife/article/details/103183674