Linux中的子shell是什么,怎么理解?

Posted 栗子~~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux中的子shell是什么,怎么理解?相关的知识,希望对你有一定的参考价值。

文章目录

前言

  如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。
  而且听说点赞的人每天的运气都不会太差,实在白嫖的话,那欢迎常来啊!!!


Linux中的子shell是什么,怎么理解?

01 子shell概念

从当前shell 环境中新开了一个shell 环境,这是新开的shell环境就是子shell,
而开启子shell的环境称为该子shell的父shell。子shell和父shell的关系其实就是子进程和父进程的关系。

02 子shell 类型

  1. fork 是复制进程,它会复制当前进程的副本,从父进程那继承了一些资源,这些资源包括内存中的内容,环境变量和变量,但是他和父进程是完全独立的,他们是一个程序的两个实例。
  2. exec 是加载另一个应用程序,替代当前运行的进程,也就是在不创建新的进程的情况下加载一个新进程,在进程执行完全后退出所在的shell环境。为了保证进程的安全,新的且独立的子进程,内容和父进程是一样的(包括变量),exec还有一个动作:在进程执行完毕后,退出exec所在的shell环境。

03 如何测试是否产生子shell

在这里我们用两个环境变量来达到测试的目的:

BASH_SUBSHELL 用来表示进入子 shell 的层级,比如处于当前 shell 时,该变量值为 0;
当在当前 shell 派生的子 shell 里时,该变量值为 1;如果该子 shell 又派生出一个子 shell,那么该变量在此间的值就为 2,以此类推。

BASHPID 用来查看当前所处BASH的PID
实例:

echo $BASHPID $BASH_SUBSHELL
echo $(echo $BASHPID $BASH_SUBSHELL)
echo $( echo $(echo $BASHPID $BASH_SUBSHELL))


这里解释一下命令替换 $() 可以产生子shell

04 什么时候不产生子shell

执行bash内置命令时,bash的内置命令默认是不开启子shell的,而是直接在当前bash 的环境中执行,如下:

echo  $BASHPID $BASH_SUBSHELL  #当前BASHPIP 和层级
let a=$BASHPID                 #BASH 内置命令 不生成新的子shell
echo  $a $BASH_SUBSHELL

注:其中有个命令,比较特殊,就是bash 命令,你可以说它创建了子shell,也可以说它没有创建子shell。

因为执行bash命令会加载各种环境配置项,为了父bash的环境得到保护而不被覆盖,
所以应该让其以子shell的方式存在。虽然fork出来的bash子进程内容完全继承父shell,但因重新加载了环境配置项,所以子shell没有继承普通变量,更准确的说是覆盖了从父shell中继承的变量。
下面可以看出bash命令后,对于BASHPID已经变了。

echo  $BASHPID $BASH_SUBSHELL
bash
echo $BASHPID $BASH_SUBSHELL

但从bash是内置命令的角度来考虑,它不会进入子shell,因为可以从BASH_SUBSHELL看出来,
所以说bash命令既可以说它产生新的子shell因为它的BASHPID有变化,也可以说没产生新的子shell,
因为它的BASH_SUBSHELL为0。

05 什么时候产生子shell

05::01 管道命令

管道使得任何命令都进入进程组,会进入子shell

05::02 执行shell脚本

执行shell脚本,如果首行为#!/bin/bash,
其实跟上面说的bash命令差不多,也可以说它产生了新的子shell。
验证1:
制作test1_1.sh 脚本

#!/bin/bash
echo $BASHPID $BASH_SUBSHELL

如果该shell脚本是在Windows环境下编写过,可以使用命令

sed -i 's/\\r$//' test1_1.sh 把^M$去掉就好

否则会报如下错误:

报错: -bash: ./test1_1.sh: /bin/bash^M: 坏的解释器: 没有那个文件或目录
chmod u+x test1_1.sh
sed -i 's/\\r$//' test1_1.sh
echo  $BASHPID
./test1_1.sh

可以发现虽然它的BASH_SUBSHELL为0,但它的BASHPID已经发生变化。

验证2:
制作test1_1.sh 脚本
定义一个全局变量 XX变量,并打印YY变量

#!/bin/bash

export XX=hello
echo $YY

看下面的操作:

我们可以发现脚本里面定的XX变量在外面没有打印,而外面定义的YY变量,在脚本里能够打印出来,
说明了执行 shell脚本的时候产生了新的子shell,因此在子shell里面定的全局变量,没办法在父shell里面获取到,因为子shell的变量不会影响到父shell。

05::03 命令替换($())

使用命令替换$()进入子shell

echo $BASHPID
echo $(echo $BASHPID)


可以发现BASHPID有改动。

即当命令行中包含了命令替换部分时,将开启一个子shell先执行这部分内容,再将执行结果返回给当前命令。

05::04 使用()组合

使用括号()的命令组合进入子shell

echo $BASHPID
(echo $BASHPID)

05::05 放入后台运行的任务

放入后台运行的任务进入子shell

echo $BASHPID
echo $BASHPID &

05::06 进程替换

进程替换"<()"进入子shell

echo $BASHPID
cat <(echo $BASHPID) 

以上是关于Linux中的子shell是什么,怎么理解?的主要内容,如果未能解决你的问题,请参考以下文章

理解Linux中子shell的概念

Linux写一个shell脚本,要实现在键盘输入一个进程号,输出这个进程号的子进程pid,怎么写?

COUNTER=$(($COUNTER+1))。。。。。。shell编程中这一个语句的理解

linux C里面的write函数的第一个参数是怎么判断的??

求问关于linux子shell的问题!

linux系统在脚本里面怎么给一个文件追加几行内容