SHELL十三问之六:exec 跟 source 差在哪?

这次先让我们从CU Shell版的一个实例贴子来谈起吧:
/T:]4p3I1
例中的提问是:BSD爱好者乐园M I�j x8lzp^?

cd /etc/aa/bb/cc可以执行,但是把这条命令写入shellshell不执行!BSD爱好者乐园;u}B'je.MU0@|
这是什么原因呀!

8O]'WyE7r6~1`1

我当时如何回答暂时别去深究,先让我们了解一下进程(process)的观念好了。
;Jv#/,gy1BSD爱好者乐园/Jrq/SYs /
首先,我们所执行的任何程序,都是由父进程(parent process)所产生出来的一个子进程(child process),子进程在结束后,将返回到父进程去。此一现像在Linux系统中被称为 forkBSD爱好者乐园 X,x+z6?-nO$q;l
当子进程被产生的时候,将会从父进程那里获得一定的资源分配、及(更重要的是)继承父进程的环境BSD爱好者乐园,W q ea8w1H%R
BSD爱好者乐园p/ZFl,T3w5d
让我们回到上一章所谈到的"环境变量"吧:
4X p:eQ4E |1
*所谓环境变量其实就是那些会传给子进程的变量。BSD爱好者乐园i q-c�` v/3b'u
简单而言,"遗传性"就是区分本地变量与环境变量的决定性指标。
2vw?&I5bo&N1BSD爱好者乐园/[;Kh/!k
然而,从遗传的角度来看,我们也不难发现环境变量的另一个重要特征:BSD爱好者乐园R�SO7C3{|h(f u#d_
*
环境变量只能从父进程到子进程单向继承。换句话说:在子进程中的环境如何变更,均不会影响父进程的环境。BSD爱好者乐园B T6Vr'S#ZJ�aiF
BSD爱好者乐园-Ks"Pi&`/@bc],zDc
接下来,再让我们了解一下命令脚本(shell script)的概念。
9t Bn3t|1
所谓的shell script讲起来很简单,就是将你平时在shell prompt后所输入的多行command line依序写入一个文件去而已。
5PC~?"dT sF1
其中再加上一些条件判断、互动界面、参数运用、函数调用、等等技巧,得以让script更加"聪明"的执行,但若撇开这些技巧不谈,我们真的可以简单的看成script只不过依次执行预先写好的命令行而已
#r*xIA!DFB1BSD爱好者乐园 o'v U7sn|%Kz
再结合以上两个概念(process + script),那应该就不难理解如下这句话的意思了:BSD爱好者乐园E V/C u&Jn
*
正常来说,当我们执行一个shell script时,其实是先产生一个sub-shell的子进程,然后sub-shell再去产生命令行的子进程。BSD爱好者乐园r.T;?K8I i!B*I
然则,那让我们回到本章开始时所提到的例子再从新思考:

qW`%q/S8^1

cd /etc/aa/bb/cc可以执行,但是把这条命令写入shellshell不执行!BSD爱好者乐园7` p;r4wr6l.ziV
这是什么原因呀!

o.hk'Xy.Z;b/r1

我当时的答案是这样的:BSD爱好者乐园1V$BS:}f7O5| xC

因为,一般我们跑的shell script是用subshell去执行的。BSD爱好者乐园/Q th.I7p#hRbA
process的观念来看,是parent process产生一个child process去执行,当child结束后,会返回parent,但parent的环境是不会因child的改变而改变的。
8U6~eq `2G _0Jg1
所谓的环境元数很多,凡举effective id, variable, workding dir等等...BSD爱好者乐园Y1I([8O+P9B
其中的workding dir ($PWD)正是楼主的疑问所在:BSD爱好者乐园IP6["YZ/2M
当用subshell来跑script的话,sub shell$PWD会因为cd而变更,
5UBw1u f4P I A R1
但当返回primary shell时,$PWD是不会变更的。BSD爱好者乐园%[ f0Kj1e,f3p:v

能够了解问题的原因及其原理是很好的,但是?如何解决问题恐怕是我们更感兴趣的﹗是吧?^_^BSD爱好者乐园t,f#/g&E1RdPYm

J)[*?h8Hg1d0`1
那好,接下来,再让我们了解一下source命令好了。
g#O(W'z{Z1
当你有了fork的概念之后,要理解source就不难:
C/QS@p$Dtp1
*所谓source就是让script在当前shell内执行、而不是产生一个sub-shell来执行。
4Di}H|)ka@.a1
由于所有执行结果均于当前shell内完成,若script的环境有所改变,当然也会改变当前环境了﹗
)/h'bc5Q-[5x1
因此,只要我们要将原本单独输入的script命令行变成source命令的参数,就可轻易解决前例提到的问题了。
2tI c T:|'^!I1
比方说,原本我们是如此执行  script的:

Q(WSX /"V5Rm1

./my.script

bS:k]f2lIB1

现在改成这样即可:BSD爱好者乐园S5T*]&WzaZ5Vr[

source ./my.script
'Ue(Whb kc4m�f(f1
或:BSD爱好者乐园R!Z]b2D%i#c[
. ./my.script

sgk'j#i `7vp1

说到这里,我想,各位有兴趣看看/etc底下的众多设定文件,应该不难理解它们被定义后,如何让其它script读取并继承了吧?
6}`Q{^i1
若然,日后你有机会写自己的script,应也不难专门指定一个设定文件以供不同的script一起"共享"...  ^_^BSD爱好者乐园8N0WE&n)ux
BSD爱好者乐园9q w P_#p ^2r.JF/]%@
okay
,到这里,若你搞得懂forksource的不同,那接下来再接受一个挑战:BSD爱好者乐园G*T?Tg1s/d~
----
exec又与source/fork有何不同呢?BSD爱好者乐园*vn3] S-}B
...要了解exec或许较为复杂,尤其扯上File Descriptor的话...
|"sJ&vi&E$y1
mk*c$a!jY sU L1
不过,简单来说:BSD爱好者乐园%U/Z {0~5b
* exec也是让script在同一个进程上执行,但是原有进程则被结束了
W p$v&L N$fEo2SD2x!]1
也就是简而言之:原有进程会否终止,就是execsource/fork的最大差异了。BSD爱好者乐园t^(e_v'd2k
BSD爱好者乐园'v0_$^o W
嗯,光是从理论去理解,或许没那么好消化,不如动手"实作+思考"来的印像深刻哦。BSD爱好者乐园�U&b/d0z {f
下面让我们写两个简单的script,分别命令为1.sh2.shBSD爱好者乐园MF2j3eBv u0F&N,?
BSD爱好者乐园/_|/`R-dfF*B
1.sh

b/QD6~v S+IM1

#!/bin/shBSD爱好者乐园R/l A.{ SOE�Mrf
A=BBSD爱好者乐园_ z,}3@jM
echo "PID for 1.sh before exec/source/fork:$$"BSD爱好者乐园"hqq x'K0t#LcN&j8w
export A
rX%|&Zr1echo "1.sh: /$A is $A"
q[{t I0m'k1case $1 inBSD爱好者乐园9ndQ_2J
        exec)
9yd-L'Y?m1                echo "using exec..."
Td3d/U|1                exec ./2.sh ;;
r@"^F/y~X1R*R;U3X1        source)
CO4~7XK~|:H.l1                echo "using source..."BSD爱好者乐园Ng!w;_[ t x
                . ./2.sh ;;
!V#s P0F3xz1        *)
wB]2I-N!r1                echo "using fork by default..."
%U"e+~xh U Q1                ./2.sh ;;BSD爱好者乐园3~ zB+p;W
esac
Q aW0Mn6a1echo "PID for 1.sh after exec/source/fork:$$"BSD爱好者乐园9J g:o"Ty!w+a G s9y
echo "1.sh: /$A is $A"
BSD爱好者乐园h9rB5X"v }

2.sh

B g6E5k!f-|b Jy1

#!/bin/shBSD爱好者乐园%] b0XP.B8F2U
echo "PID for 2.sh: $$"BSD爱好者乐园m0tI!L#p{8AI
echo "2.sh get /$A=$A from 1.sh"BSD爱好者乐园:C xi;w?IFL
A=CBSD爱好者乐园 js4G7[Jn/,r;/
export ABSD爱好者乐园+R-kSH0C0Qm6M%K&}
echo "2.sh: /$A is $A"
BSD爱好者乐园Y4uf/E:SN3P2c

然后,分别跑如下参数来观察结果:

G%[$b9C,uR3b_O aw1

$ ./1.sh fork

6dj1mw0NH,`1

PID for 1.sh before exec/source/fork:531

Nm�R PWh0p:k1

1.sh: $A is BBSD爱好者乐园(D4[(c6hO/+t^&JI

using fork by default...BSD爱好者乐园t8x b�aN"P+^&q|

PID for 2.sh:532

5OA eyo1

2.sh get $A=B from 1.shBSD爱好者乐园OL.Kd h4W(h

2.sh: $A is CBSD爱好者乐园^`T8s z(z&pG

PID for 1.sh after exec/source/fork:531

n4K2p7y A?!N1

1.sh: $A is B

:z b op[$a,bN1

 BSD爱好者乐园 KS)}1_x8x

$ ./1.sh source

5dB7C.Q!Rh!L1

PID for 1.sh before exec/source/fork:533

'Q(B,t-kQ2@5z1

1.sh: $A is BBSD爱好者乐园-|-_B!v@|3y R x O

using source...BSD爱好者乐园-R%~ aKz

PID for 2.sh:533

-N.W_�JN:h1

2.sh get $A=B from 1.sh

5w"s+A_y}e�D~1

2.sh: $A is C

'y SSL2q1

PID for 1.sh after exec/source/fork:533

)JH4G F,K(t4O1

1.sh: $A is C

7U5o ] Q1|3}1

 BSD爱好者乐园`TE OI#iSp�t z

$ ./1.sh exec

Pq%q|`3X1

PID for 1.sh before exec/source/fork:537BSD爱好者乐园6QK:|:u%an:x,[P

1.sh: $A is BBSD爱好者乐园Y,Qc(Ig D v w1q6H5iJ

using exec...BSD爱好者乐园O;H$k q6pqM8D'jH"r

PID for 2.sh:537BSD爱好者乐园f em4k5E5nk*k(FX

2.sh get $A=B from 1.shBSD爱好者乐园h4D/Cp+WA`

2.sh: $A is C

RTK9PD|X;V:eq1

############BSD爱好者乐园d3@W$b l

echo "PID for 1.sh after exec/source/fork:$$"
3jV_B-t.~Al"i1echo "1.sh: /$A is $A"
BSD爱好者乐园1X!F)`+E$K+OMk

已经不会执行了,1.sh的进程已经没了。

yn7qoV,w:M8bI K_1

##############

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值