Linux命令+shell脚本大全:shell 的父子关系

2023-11-05

用于登录某个虚拟控制器终端或在GUI中运行终端仿真器时所启动的默认的交互shell,是一
个父shell。本书到目前为止都是父shell提供CLI提示符,然后等待命令输入。
在CLI提示符后输入 /bin/bash 命令或其他等效的 bash 命令时,会创建一个新的shell程序。
这个shell程序被称为子shell(child shell)。子shell也拥有CLI提示符,同样会等待命令输入。
当输入 bash 、生成子shell的时候,你是看不到任何相关的信息的,因此需要另一条命令帮助
我们理清这一切。第4章中讲过的 ps 命令能够派上用场,在生成子shell的前后配合选项 -f 来使用。

$ ps -f
UID PID PPID C STIME TTY TIME CMD
501 1841 1840 0 11:50 pts/0 00:00:00 -bash
501 2429 1841 4 13:44 pts/0 00:00:00 ps -f
$
$ bash
$
$ ps -f
UID PID PPID C STIME TTY TIME CMD
501 1841 1840 0 11:50 pts/0 00:00:00 -bash
501 2430 1841 0 13:44 pts/0 00:00:00 bash
501 2444 2430 1 13:44 pts/0 00:00:00 ps -f
$

第一次使用 ps -f 的时候,显示出了两个进程。其中一个进程的进程ID是 1841 (第二列),
运行的是bash shell程序(最后一列)。另一个进程(进程ID为 2429 )对应的是命令 ps -f 。

说明

进程就是正在运行的程序。bash shell是一个程序,当它运行的时候,就成为了一个进程。
一个运行着的shell就是某种进程而已。因此,在说到运行一个bash shell的时候,你经常会
看到“shell”和“进程”这两个词交换使用。

输入命令 bash 之后,一个子shell就出现了。第二个 ps -f 是在子shell中执行的。可以从显示
结果中看到有两个bash shell程序在运行。第一个bash shell程序,也就是父shell进程,其原始进程
ID是 1814 。第二个bash shell程序,即子shell进程,其PID是 2430 。注意,子shell的父进程ID(PPID)
是 1841 ,指明了这个父shell进程就是该子shell的父进程。图5-1展示了这种关系。

 

在生成子shell进程时,只有部分父进程的环境被复制到子shell环境中。这会对包括变量在内
的一些东西造成影响,我们会在第6章中谈及相关的内容。
子shell(child shell,也叫subshell)可以从父shell中创建,也可以从另一个子shell中创建。

$ ps -f
UID PID PPID C STIME TTY TIME CMD
501 1841 1840 0 11:50 pts/0 00:00:00 -bash
501 2532 1841 1 14:22 pts/0 00:00:00 ps -f
$
$ bash
$
$ bash
$
$ bash
$
$ ps --forest
PID TTY TIME CMD
1841 pts/0 00:00:00 bash
2533 pts/0 00:00:00 \_ bash
2546 pts/0 00:00:00 \_ bash
2562 pts/0 00:00:00 \_ bash
2576 pts/0 00:00:00 \_ ps
$


在上面的例子中, bash 命令被输入了三次。这实际上创建了三个子shell。 ps -forest 命令
展示了这些子shell间的嵌套结构。图5-2中也展示了这种关系。 

ps -f 命令也能够表现子shell的嵌套关系,因为它能够通过PPID列显示出谁是谁的父进程。

$ ps -f
UID PID PPID C STIME TTY TIME CMD
501 1841 1840 0 11:50 pts/0 00:00:00 -bash
501 2533 1841 0 14:22 pts/0 00:00:00 bash
501 2546 2533 0 14:22 pts/0 00:00:00 bash
501 2562 2546 0 14:24 pts/0 00:00:00 bash
501 2585 2562 1 14:29 pts/0 00:00:00 ps -f
$

bash shell程序可使用命令行参数修改shell启动方式。表5-1列举了bash中可用的命令行参数。 

 

可以输入 man bash 获得关于 bash 命令的更多帮助信息,了解更多的命令行参数。 bash
--help 命令也会提供一些额外的协助。
可以利用 exit 命令有条不紊地退出子shell。 

$ exit
exit
$
$ ps --forest
PID TTY TIME CMD
1841 pts/0 00:00:00 bash
2533 pts/0 00:00:00 \_ bash
2546 pts/0 00:00:00 \_ bash
2602 pts/0 00:00:00 \_ ps
$
$ exit
exit
$
$ exit
exit
$
$ ps --forest
PID TTY TIME CMD
1841 pts/0 00:00:00 bash
2604 pts/0 00:00:00 \_ ps
$

exit 命令不仅能退出子shell,还能用来登出当前的虚拟控制台终端或终端仿真器软件。只需
要在父shell中输入 exit ,就能够从容退出CLI了。
运行shell脚本也能够创建出子shell。在第11章,你将会学习到相关话题的更多知识。
就算是不使用bash shell命令或是运行shell脚本,你也可以生成子shell。一种方法就是使用进
程列表。


5.2.1 进程列表
你可以在一行中指定要依次运行的一系列命令。这可以通过命令列表来实现,只需要在命令
之间加入分号(;)即可。

$ pwd ; ls ; cd /etc ; pwd ; cd ; pwd ; ls
/home/Christine
Desktop Downloads Music Public Videos
Documents junk.dat Pictures Templates
/etc
/home/Christine
Desktop Downloads Music Public Videos
Documents junk.dat Pictures Templates
$

在上面的例子中,所有的命令依次执行,不存在任何问题。不过这并不是进程列表。命令列
表要想成为进程列表,这些命令必须包含在括号里。

$ (pwd ; ls ; cd /etc ; pwd ; cd ; pwd ; ls)
/home/Christine
Desktop Downloads Music Public Videos
Documents junk.dat Pictures Templates
/etc
/home/Christine
Desktop Downloads Music Public Videos
Documents junk.dat Pictures Templates
$

尽管多出来的括号看起来没有什么太大的不同,但起到的效果确是非同寻常。括号的加入使
命令列表变成了进程列表,生成了一个子shell来执行对应的命令。
说明 进程列表是一种命令分组(command grouping)。另一种命令分组是将命令放入花括号中,
并在命令列表尾部加上分号(;)。语法为 { command; } 。使用花括号进行命令分组并不
会像进程列表那样创建出子shell。
要想知道是否生成了子shell,得借助一个使用了环境变量的命令。(环境变量会在第6章中详
述。)这个命令就是 echo $BASH_SUBSHELL 。如果该命令返回 0 ,就表明没有子shell。如果返回
1 或者其他更大的数字,就表明存在子shell。
下面的例子中使用了一个命令列表,列表尾部是 echo $BASH_SUBSHELL 。

$ pwd ; ls ; cd /etc ; pwd ; cd ; pwd ; ls ; echo $BASH_SUBSHELL
/home/Christine
Desktop Downloads Music Public Videos
Documents junk.dat Pictures Templates
/etc
/home/Christine
Desktop Downloads Music Public Videos
Documents junk.dat Pictures Templates
0

在命令输出的最后,显示的是数字 0 。这就表明这些命令不是在子shell中运行的。
要是使用进程列表的话,结果就不一样了。在列表最后加入 echo $BASH_SUBSHELL 。
$ (pwd ; ls ; cd /etc ; pwd ; cd ; pwd ; ls ; echo $BASH_SUBSHELL)
/home/Christine
Desktop Downloads Music Public Videos
Documents junk.dat Pictures Templates
/etc
/home/Christine
Desktop Downloads Music Public Videos
Documents junk.dat Pictures Templates
1
这次在命令输入的最后显示出了数字 1 。这表明的确创建了子shell,并用于执行这些命令。
所以说,命令列表就是使用括号包围起来的一组命令,它能够创建出子shell来执行这些命令。
你甚至可以在命令列表中嵌套括号来创建子shell的子shell。
$ ( pwd ; echo $BASH_SUBSHELL)
/home/Christine
1
$ ( pwd ; (echo $BASH_SUBSHELL))
/home/Christine
2
注意,在第一个进程列表中,数字 1 表明了一个子shell,这个结果和预期的一样。但是在第
二个进程列表中,在命令 echo $BASH_SUBSHELL 外面又多出了一对括号。这对括号在子shell中

产生了另一个子shell来执行命令。因此数字 2 表明的就是这个子shell。
在shell脚本中,经常使用子shell进行多进程处理。但是采用子shell的成本不菲,会明显拖慢
处理速度。在交互式的CLI shell会话中,子shell同样存在问题。它并非真正的多进程处理,因为
终端控制着子shell的I/O。
5.2.2 别出心裁的子 shell 用法
在交互式的shell CLI中,还有很多更富有成效的子shell用法。进程列表、协程和管道(第11
章会讲到)都利用了子shell。它们都可以有效地在交互式shell中使用。
在交互式shell中,一个高效的子shell用法就是使用后台模式。在讨论如果将后台模式与子shell
搭配使用之前,你得先搞明白什么是后台模式。
1. 探索后台模式
在后台模式中运行命令可以在处理命令的同时让出CLI,以供他用。演示后台模式的一个经
典命令就是 sleep 。
sleep 命令接受一个参数,该参数是你希望进程等待(睡眠)的秒数。这个命令在脚本中常
用于引入一段时间的暂停。命令 sleep 10 会将会话暂停10秒钟,然后返回shell CLI提示符。
$ sleep 10
$
要想将命令置入后台模式,可以在命令末尾加上字符 & 。把 sleep 命令置入后台模式可以让我
们利用 ps 命令来小窥一番。
$ sleep 3000&
[1] 2396
$ ps -f
UID PID PPID C STIME TTY TIME CMD
christi+ 2338 2337 0 10:13 pts/9 00:00:00 -bash
christi+ 2396 2338 0 10:17 pts/9 00:00:00 sleep 3000
christi+ 2397 2338 0 10:17 pts/9 00:00:00 ps -f
$
sleep 命令会在后台( & )睡眠3000秒(50分钟)。当它被置入后台,在shell CLI提示符返回
之前,会出现两条信息。第一条信息是显示在方括号中的后台作业(background job)号( 1 )。
第二条是后台作业的进程ID( 2396) 。
ps 命令用来显示各种进程。我们可以注意到命令 sleep 3000 已经被列出来了。在第二列显
示的进程ID(PID)和命令进入后台时所显示的PID是一样的,都是 2396 。
除了 ps 命令,你也可以使用 jobs 命令来显示后台作业信息。 jobs 命令可以显示出当前运行
在后台模式中的所有用户的进程(作业)。
$ jobs
[1]+ Running sleep 3000 &
$
jobs 命令在方括号中显示出作业号( 1 )。它还显示了作业的当前状态( running )以及对应的命令( sleep 3000 & )。
利用 jobs 命令的 -l (字母L的小写形式)选项,你还能够看到更多的相关信息。除了默认信
息之外, -l 选项还能够显示出命令的PID。
$ jobs -l
[1]+ 2396 Running sleep 3000 &
$
一旦后台作业完成,就会显示出结束状态。
[1]+ Done sleep 3000 &
$

窍门

需要提醒的是:后台作业的结束状态可未必会一直等待到合适的时候才现身。当作业结
束状态突然出现在屏幕上的时候,你可别吃惊啊。


后台模式非常方便,它可以让我们在CLI中创建出有实用价值的子shell。
2. 将进程列表置入后台
之前说过,进程列表是运行在子shell中的一条或多条命令。使用包含了 sleep 命令的进程列
表,并显示出变量 BASH_SUBSHELL ,结果和期望的一样。
$ (sleep 2 ; echo $BASH_SUBSHELL ; sleep 2)
1
$
在上面的例子中,有一个2秒钟的暂停,显示出的数字 1 表明只有一个子shell,在返回提示符
之前又经历了另一个2秒钟的暂停。没什么大事。
将相同的进程列表置入后台模式会在命令输出上表现出些许不同。
$ (sleep 2 ; echo $BASH_SUBSHELL ; sleep 2)&
[2] 2401
$ 1
[2]+ Done ( sleep 2; echo $BASH_SUBSHELL; sleep 2 )
$
把进程列表置入后台会产生一个作业号和进程ID,然后返回到提示符。不过奇怪的是表明单
一级子shell的数字 1 显示在了提示符的旁边!不要不知所措,只需要按一下回车键,就会得到另
一个提示符。
在CLI中运用子shell的创造性方法之一就是将进程列表置入后台模式。你既可以在子shell中
进行繁重的处理工作,同时也不会让子shell的I/O受制于终端。
当然了, sleep 和 echo 命令的进程列表只是作为一个示例而已。使用 tar (参见第4章)创
建备份文件是有效利用后台进程列表的一个更实用的例子。

$ (tar -cf Rich.tar /home/rich ; tar -cf My.tar /home/christine)&
[3] 2423
$

将进程列表置入后台模式并不是子shell在CLI中仅有的创造性用法。协程就是另一种方法。
3. 协程
协程可以同时做两件事。它在后台生成一个子shell,并在这个子shell中执行命令。
要进行协程处理,得使用 coproc 命令,还有要在子shell中执行的命令。
$ coproc sleep 10
[1] 2544
$
除了会创建子shell之外,协程基本上就是将命令置入后台模式。当输入 coproc 命令及其参
数之后,你会发现启用了一个后台作业。屏幕上会显示出后台作业号( 1 )以及进程ID( 2544 )。
jobs 命令能够显示出协程的处理状态。
$ jobs
[1]+ Running coproc COPROC sleep 10 &
$
在上面的例子中可以看到在子shell中执行的后台命令是 coproc COPROC sleep 10 。 COPROC
是 coproc 命令给进程起的名字。你可以使用命令的扩展语法自己设置这个名字。
$ coproc My_Job { sleep 10; }
[1] 2570
$
$ jobs
[1]+ Running coproc My_Job { sleep 10; } &
$
通过使用扩展语法,协程的名字被设置成 My_Job 。这里要注意的是,扩展语法写起来有点
麻烦。必须确保在第一个花括号( { )和命令名之间有一个空格。还必须保证命令以分号(;)结
尾。另外,分号和闭花括号( } )之间也得有一个空格。
说明 协程能够让你尽情发挥想象力,发送或接收来自子shell中进程的信息。只有在拥有多个协
程的时候才需要对协程进行命名,因为你得和它们进行通信。否则的话,让 coproc 命令
将其设置成默认的名字 COPROC 就行了。
你可以发挥才智,将协程与进程列表结合起来产生嵌套的子shell。只需要输入进程列表,然
后把命令 coproc 放在前面就行了。

$ coproc ( sleep 10; sleep 2 )
[1] 2574
$
$ jobs
[1]+ Running coproc COPROC ( sleep 10; sleep 2 ) &
$
$ ps --forest
PID TTY TIME CMD
2483 pts/12 00:00:00 bash
2574 pts/12 00:00:00 \_ bash
2575 pts/12 00:00:00 | \_ sleep
2576 pts/12 00:00:00 \_ ps
$

记住,生成子shell的成本不低,而且速度还慢。创建嵌套子shell更是火上浇油!
在命令行中使用子shell能够获得灵活性和便利。要想获得这些优势,重要的是理解子shell的
行为方式。对于命令也是如此。在下一节中,我们将研究内建命令与外部命令之间的行为差异。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux命令+shell脚本大全:shell 的父子关系 的相关文章

  • paste0函数在R语言中的应用

    paste0函数在R语言中的应用 在R语言中 paste0函数是一个非常有用的函数 它可以将多个输入组合成一个字符串 这个函数的使用非常简单 只需要将要组合的内容作为参数传递给paste0函数即可 在本文中 我们将通过实例来演示paste0
  • 全球及中国装备制造产业投资战略及产销需求预测报告2021-2027年版

    全球及中国装备制造产业投资战略及产销需求预测报告2021 2027年版 HS HS HS HS HS HS HS HS HS HS HS HS 修订日期 2021年10月 搜索鸿晟信合研究院查看官网更多内容 第一章 装备制造业概述 1 1
  • Redraiment的走法

    题目描述 题目描述 Redraiment是走梅花桩的高手 Redraiment总是起点不限 从前到后 往高的桩子走 但走的步数最多 不知道为什么 你能替Redraiment研究他最多走的步数吗 样例输入 6 2 5 1 5 4 5 样例输出

随机推荐

  • LabVIEW结合神经网络在图像目标检测中的应用

    神经网络在图像识别中的应用 摘要 随着大数据时代的快速发展 图像识别技术的重要性与日俱增 大量的数据集和强大的服务器计算能力 更是如虎添翼 相比传统的图像分类方法已经无法满足用户对于对图像分类灵活性和速度上的要求 甚至在复杂环境下 传统算法
  • Mac下安装Metasploit

    今天鼓捣Metasploit在Mac上的安装 首先下载pkg文件 http osx metasploit com metasploitframework latest pkg 接着 cd opt metasploit framework b
  • picker多列可选

    npm install usui save import usui from usui Vue use usui this usui picker label 1 value 1 label 2 value 2 label 3 value
  • androidstudio 导入git问题 is under Git, but is not registered in the Settings

    从git项目第一次导入数据到本地可能会出现以上问题 1 针对此图 首先选择Configure 2 针对上图选择加号 然后选择指定的项目路径以及类型 点击OK apply
  • Java案例:实现杨辉三角

    Java案例 实现杨辉三角 前言 本篇文章我将讲述使用Java实现杨辉三角的实现 而且可以根据用户输入的正整数输出指定行数的杨辉三角 一 杨辉三角是什么 杨辉三角 是二项式系数在三角形中的一种几何排列 中国南宋数学家杨辉1261年所著的 详
  • dockerfile

    当我在dockerfile里面想安装torchvision WORKDIR vision 0 8 1 WORKDIR相当于cd 进入文件夹执行 RUN python3 setup py install user 想要安装时 报错 Trace
  • LayUi 折叠表格

    表格会以代码的形式写到里面 大家可以将代码copy到项目中新建一个HTML尝试 下面用到的JS都会进行展示JS的内容 可以完全还原我当时的环境 lt include common layout html gt lt header gt
  • jQuery中的.bind()、.live()和.delegate()之间区别分析

    DOM树 首先 可视化一个HMTL文档的DOM树是很有帮助的 一个简单的HTML页面看起来就像是这个样子 事件冒泡 又称事件传播 当我们点击一个链接时 其触发了链接元素的单击事件 该事件则引发任何我们已绑定到该元素的单击事件上的函数的执行
  • 机器学习-KNN近邻算法

    参看文章 机器学习 周志华 机器学习实战 Peter Harrington 统计学习方法 李航 算法介绍 k近邻学习是一种常用的监督学习方法 其工作机制如下 给定测试样本 基于某种距离度量 曼哈顿距离 欧氏距离 切比雪夫距离 Lp距离 Mi
  • thinking 程序员思维习惯 .

    程序员 天职 gt 用计算机解决复杂 重复性 精确性问题 创造性 gt 养成一遇到问题 麻烦 应通过google相关的答案或 工具来解决 或写程序来解决的方法的思维习惯 case 导数程序 多库之间的同步 gt add UI 技术人员使用
  • 软件安全性测试

    软件安全性是一个广泛而复杂的主题 每一个新的软件总可能有完全不符合所有已知模式的新型安全性缺陷出现 要避免因安全性缺陷问题受各种可能类型的攻击是不切实际的 在软件安全测试时 运用一组好的原则来避免不安全的软件上市 避免不安全软件受攻击 就显
  • 如何在pycharm上安装tensorflow

    TensorFlow 是一个基于数据流编程 dataflow programming 的符号数学系统 被广泛应用于各类机器学习 machine learning 算法的编程实现 其前身是谷歌的神经网络算法库DistBelief Tensor
  • CMake命令之add_custom_comand 和 add_custom_target

    一 背景 在很多时候 需要在cmake中创建一些目标 如clean copy等等 这就需要通add custom target来指定 而add custom command则可以用来完成对add custom target生成的target
  • 一个变量越界导致破坏堆栈的bug

    前一段时间在商用系统上出现了core dump 原因是由于一个局部变量写越界导致堆栈被破坏了 在这里 我把这个bug分享一下 希望给需要的朋友一点帮助 简化的代码如下 typedef struct A void func1 char p v
  • 投资还是创业?我以亲身经验告诉你真相

    编者按 本文作者徐薇 前创新工场投资总监 现创业中 做女性生活方式社区电商 本文原载于徐薇的个人公众号 人生异想 life essay 授权 36 氪转载 欢迎交流讨论 最近真是很巧 有好几个朋友在考虑做新的事业选择 来找我聊 聊完之后 大
  • 腾讯云学生服务器2核2G和4核8G申请详细流程

    腾讯云学生服务器2核2G和4核8G申请详细流程 学生机申请流程 腾讯云学生服务器优惠活动 轻量应用服务器2核2G学生价30元3个月 58元6个月 112元一年 轻量应用服务器4核8G配置191 1元3个月 352 8元6个月 646 8元一
  • ymPrompt消息提示组件 2.0版

    组件功能介绍 1 调用方式简单 直接使用ymPrompt alert 的方式调用 传入相应的参数即可 2 兼容IE6 0 FF1 5 Opear9 在Opear下显示有一个小缺陷 兼容HTML4 XHTML1 0页面渲染模式 3 完全的CS
  • 图像超分辨率重建原理学习

    原文链接 https blog csdn net gwplovekimi article details 83041627 目录 超分辨率 Super Resolution SR 传统的图像超分辨率重建技术简介 基于插值的图像超分 基于重建
  • JDK20又来了!你还在用JDK8么?

    文章目录 前言 JDK 20发布 JDK20下载 JDK 20新特性 矢量API 虚拟线程 第二次优化 结构化并发 Scoped values 作用域值 记录模式 第二次优化 外部函数和内存API switch语句和表达式的模式匹配 写在最
  • Linux命令+shell脚本大全:shell 的父子关系

    用于登录某个虚拟控制器终端或在GUI中运行终端仿真器时所启动的默认的交互shell 是一 个父shell 本书到目前为止都是父shell提供CLI提示符 然后等待命令输入 在CLI提示符后输入 bin bash 命令或其他等效的 bash