linux中fork,source和exec的区别

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux中fork,source和exec的区别相关的知识,希望对你有一定的参考价值。

exec和source都属于bash内部命令(builtins commands),在bash下输入man exec或man source可以查看所有的内部命令信息。

bash shell的命令分为两类:外部命令和内部命令。外部命令是通过系统调用或独立的程序实现的,如sed、awk等等。内部命令是由特殊的文件格式(.def)所实现,如cd、history、exec等等。
在说明exec和source的区别之前,先说明一下fork的概念。
fork是linux的系统调用,用来创建子进程(child process)。子进程是父进程(parent process)的一个副本,从父进程那里获得一定的资源分配以及继承父进程的环境。子进程与父进程唯一不同的地方在于pid(process id)。
环境变量(传给子进程的变量,遗传性是本地变量和环境变量的根本区别)只能单向从父进程传给子进程。不管子进程的环境变量如何变化,都不会影响父进程的环境变量。
shell script:
有两种方法执行shell scripts,一种是新产生一个shell,然后执行相应的shell scripts;一种是在当前shell下执行,不再启用其他shell。
新产生一个shell然后再执行scripts的方法是在scripts文件开头加入以下语句
#!/bin/sh
一般的script文件(.sh)即是这种用法。这种方法先启用新的sub-shell(新的子进程),然后在其下执行命令。
另外一种方法就是上面说过的source命令,不再产生新的shell,而在当前shell下执行一切命令。
source:
source命令即点(.)命令。
在bash下输入man source,找到source命令解释处,可以看到解释"Read and execute commands from filename in the current shell environment and ..."。从中可以知道,source命令是在当前进程中执行参数文件中的各个命令,而不是另起子进程(或sub-shell)。source filename or .filename 执行filename中的命令。
exec:
在bash下输入man exec,找到exec命令解释处,可以看到有"No new process is created."这样的解释,这就是说exec命令不产生新的子进程。那么exec与source的区别是什么呢?
exec命令在执行时会把当前的shell process关闭,然后换到后面的命令继续执行。
======================================================================================================================
下面我们写个脚本来测试一下,这样你就会很容易的读懂我上面所说的东西~
1.sh

1
2
3

#!/bin/bashA=Becho "PID for 1.sh before exec/source/fork:
"exportAecho"1.sh:$Ais$A"case$1inexec)echo"usingexec..."exec./2.sh;;source)echo"usingsource..."../2.sh;;∗)echo"usingforkbydefault..."./2.sh;;esacecho"PIDfor1.shafterexec/source/fork:
"echo "1.sh: \\$A is $A"

2.sh

1
2
3
4
5
6

#!/bin/bash
echo "PID for 2.sh: $$"
echo "2.sh get \\$A=$A from 1.sh"
A=C
export A
echo "2.sh: \\$A is $A"

=================》》》》》》》》》》》
测试结果:
[root@node2 ~]$ ./1.sh fork
PID for 1.sh before exec/source/fork:10175
1.sh: $A is B
using fork by default...
PID for 2.sh: 10176
2.sh get $A=B from 1.sh
2.sh: $A is C
PID for 1.sh after exec/source/fork:10175
1.sh: $A is B
=============================================
[root@node2 ~]$ ./1.sh source
PID for 1.sh before exec/source/fork:10185
1.sh: $A is B
using source...
PID for 2.sh: 10185
2.sh get $A=B from 1.sh
2.sh: $A is C
PID for 1.sh after exec/source/fork:10185
1.sh: $A is C
=============================================
[root@node2 ~]$ ./1.sh exec
PID for 1.sh before exec/source/fork:10194
1.sh: $A is B
using exec...
PID for 2.sh: 10194
2.sh get $A=B from 1.sh
2.sh: $A is C
[cpsuser@cps-svr-153 zy]$
=============================================
从以上结果可以看出:
1.执行source和exec的过程中没有产生新的进程,而fork是默认的运行方式,在运行的过程中会产生新的进程,也就是子进程
2.source和exec的区别在于exec执行完毕后没有输出进程,也就是说运行完毕2.sh后直接退出了,没有返回1.sh
3.fork和source的最后一句输出分别为:1.sh: $A is B (fork,说明它运行的环境不一样,要不然输出的应该是C)
1.sh: $A is C(source,说明从始至终都是在一个shell中执行)
小节:
source 指定脚本中的命令在同一个shell中运行。(默认shell中的命令都是创建sub-shell,然后执行。执行完后,返回父shell)
fork 就是创建sub-shell运行脚本中的命令,和默认运行方式相同。
exec 和source相似,区别就是,运行完毕命令后退出,不会返回父shell
参考技术A shell的命令可以分为内部命令和外部命令. 内部命令是由特殊的文件格式.def实现的,如cd,ls等.而外部命令是通过系统调用或独立程序实现的,如awk,sed. source和exec都是内部命令.

fork

使用 fork 方式运行 script 时, 就是让 shell(parent process) 产生一个 child process
去执行该 script, 当 child process 结束后, 会返回 parent process,但 parent process
的环境是不会因 child process 的改变而改变的.

source
使用 source 方式运行 script
时, 就是让 script 在当前 process 内执行, 而不是产生一个 child process 来执行. 由于所有执行结果均于当前
process 内完成,若 script 的环境有所改变, 当然也会改变当前 process 环境了.
source ./my.sh 或 . ./my.sh

exec
使用 exec 方式运行script时, 它和 source 一样, 也是让 script 在当前process内执行, 但是 process 内的原代码剩下部分将被终止. 同样, process 内的环境随script 改变而改变.

结论:通常如果我们执行时,都是默认为fork的。大家可以通过pstree命令看看关于父子进程的关系。如上,如果想让父进程得到子进程的环境变量,就是source方式了

fork ( /directory/script.sh)

fork是最普通的,
就是直接在脚本里面用/directory/script.sh来调用script.sh这个脚本.运行的时候开一个sub-shell执行调用的脚
本,sub-shell执行的时候, parent-shell还在。sub-shell执行完毕后返回parent-shell.
sub-shell从parent-shell继承环境变量.但是sub-shell中的环境变量不会带回parent-shell
source (source /directory/script.sh)
与fork的区别是不新开一个sub-shell来执行被调用的脚本,而是在同一个shell中执行. 所以被调用的脚本中声明的变量和环境变量, 都可以在主脚本中得到和使用.
exec (exec /directory/script.sh)
exec与fork不同,不需要新开一个sub-shell来执行被调用的脚本. 被调用的脚本与父脚本在同一个shell内执行。但是使用exec调用一个新脚本以后, 父脚本中exec行之后的内容就不会再执行了。这是exec和source的区别

1.sh
代码:
#!/bin/bash
A=B
echo "PID for 1.sh before exec/source/fork: $$"
export A
echo "1.sh: \$A is $A"
case $1 in
exec)
echo "using exec..."
exec ./2.sh ;;
source)
echo "using source..."
. ./2.sh ;;
*)
echo "using fork by default..."
./2.sh ;;
esac
echo "PID for 1.sh after exec/source/fork: $$"
echo "1.sh: \$A is $A"

2.sh
代码:
#!/bin/bash
echo "PID for 2.sh: $$"
echo "2.sh get \$A=$A from 1.sh"
A=C
export A
echo "2.sh: \$A is $A"

然后,分别跑如下参数来观察结果:
$ ./1.sh fork
$ ./1.sh source
$ ./1.sh exec

linux中fork, source和exec的区别

 

转:linux中fork, source和exec的区别

shell的命令可以分为内部命令和外部命令. 内部命令是由特殊的文件格式.def实现的,如cd,ls等.而外部命令是通过系统调用或独立程序实现的,如awk,sed. source和exec都是内部命令.

fork
   使用 fork 方式运行 script 时, 就是让 shell(parent process) 产生一个 child process 去执行该 script, 当 child process 结束后, 会返回 parent process,但 parent process 的环境是不会因 child process 的改变而改变的.

source
   使用 source 方式运行 script 时, 就是让 script 在当前 process 内执行, 而不是产生一个 child process 来执行. 由于所有执行结果均于当前 process 内完成,若 script 的环境有所改变, 当然也会改变当前 process 环境了.
source ./my.sh 或 . ./my.sh
 
exec
   使用 exec 方式运行script时, 它和 source 一样, 也是让 script 在当前process内执行, 但是 process 内的原代码剩下部分将被终止. 同样, process 内的环境随script 改变而改变.

结论:通常如果我们执行时,都是默认为fork的。大家可以通过pstree命令看看关于父子进程的关系。如上,如果想让父进程得到子进程的环境变量,就是source方式了

* fork ( /directory/script.sh)
    fork是最普通的, 就是直接在脚本里面用/directory/script.sh来调用script.sh这个脚本.运行的时候开一个sub-shell执行调用的脚 本,sub-shell执行的时候, parent-shell还在。sub-shell执行完毕后返回parent-shell. sub-shell从parent-shell继承环境变量.但是sub-shell中的环境变量不会带回parent-shell
* source (source /directory/script.sh)
   与fork的区别是不新开一个sub-shell来执行被调用的脚本,而是在同一个shell中执行. 所以被调用的脚本中声明的变量和环境变量, 都可以在主脚本中得到和使用.
* exec (exec /directory/script.sh)
    exec与fork不同,不需要新开一个sub-shell来执行被调用的脚本. 被调用的脚本与父脚本在同一个shell内执行。但是使用exec调用一个新脚本以后, 父脚本中exec行之后的内容就不会再执行了。这是exec和source的区别

exp:

1.sh 
代码: 

 

#!/bin/bash 
A=B 
echo "PID for 1.sh before exec/source/fork: $$" 
export A 
echo "1.sh: \$A is $A" 
case $1 in 
        exec) 
                echo "using exec..." 
                exec ./2.sh ;; 
        source) 
                echo "using source..." 
                . ./2.sh ;; 
        *) 
                echo "using fork by default..." 
                ./2.sh ;; 
esac 
echo "PID for 1.sh after exec/source/fork: $$" 
echo "1.sh: \$A is $A" 

 

2.sh 
代码: 

#!/bin/bash 
echo "PID for 2.sh: $$" 
echo "2.sh get \$A=$A from 1.sh" 
A=C 
export A 
echo "2.sh: \$A is $A" 

然后,分別跑如下参数来观察结果: 
$ ./1.sh fork 
$ ./1.sh source 
$ ./1.sh exec

#fork下主进程(PID:8523)环境变量为改变,并且子进程(PID:8524)执行完毕后回到主进程
[[email protected] ~]# ./1.sh fork
PID for 1.sh before exec/source/fork:8523
1.sh: $A is B
using fork by default...
PID for 2.sh: 8524
2.sh get $A=B from 1.sh
2.sh: $A is C
PID for 1.sh after exec/source/fork:8523
1.sh: $A is B

#source下进程环境变量改变,1.sh和2.sh的PID均为8530,表明在同一进程下执行
[[email protected] ~]# ./1.sh source
PID for 1.sh before exec/source/fork:8530
1.sh: $A is B
using source...
PID for 2.sh: 8530
2.sh get $A=B from 1.sh
2.sh: $A is C
PID for 1.sh after exec/source/fork:8530
1.sh: $A is C

#exec下环境变量改变;1.sh和2.sh的PID虽然一样,但是执行2.sh完毕后,并没有回到原进程中继续执行剩余代码;可见主脚本在调用执行exec之后就退出了,余下代码也不会被执行了。
[[email protected] ~]# ./1.sh exec
PID for 1.sh before exec/source/fork:8534
1.sh: $A is B
using exec...
PID for 2.sh: 8534
2.sh get $A=B from 1.sh
2.sh: $A is C

 

 

 

***********************************************************

 学习永远不晚。——高尔基

***********************************************************

 

























以上是关于linux中fork,source和exec的区别的主要内容,如果未能解决你的问题,请参考以下文章

linux中fork, source和exec的区别

shell中sh, exec, source, fork, ./的区别

fork exec source的区别

在传统的 Linux fork-exec 中使用 _exit() 和 exit() 有啥区别?

Linux中的exec和source有什么区别呢?

shell调用另一个脚本的三种方式fork/exec/source