Shell如何执⾏命令
2.1. 执⾏交互式命令
⽤户在命令⾏输⼊命令后,⼀般情况下Shell会fork并exec该命令,但是Shell的内建命令例外,执⾏内建命令相当于调⽤Shell进程中的⼀个函数,并不创建新的进程。以前学过的cd、alias、umask、exit等命令即是内建命令,凡是⽤which命令查不到程序⽂件所在位置的命令都是内建命令,内建命令没有单独的man⼿册,要在man⼿册中查看内建命令,应该
$ man bash-builtins
本节会介绍很多内建命令,如export、shift、if、eval、[、for、while等等。内建命令虽然不创建新的进程,但也会有Exit Status,通常也⽤0表⽰成功⾮零表⽰失败,虽然内建命令不创建新的进程,但执⾏结束后也会有⼀个状态码,也可以⽤特殊变量$?读出。
习题
1、在完成时也许有的读者已经试过了,在⾃⼰实现的Shell中不能执⾏cd命令,因为cd是⼀个内建命令,没有程序⽂件,不能⽤exec执⾏。现在请完善该程序,实现cd命令的功能,⽤chdir(2)函数可以改变进程的当前⼯作⽬录。
2、思考⼀下,为什么cd命令要实现成内建命令?可不可以实现⼀个独⽴的cd程序,例如/bin/cd,就像/bin/ls⼀样?
2.2. 执⾏脚本
⾸先编写⼀个简单的脚本,保存为script.sh:
例 31.1. 简单的Shell脚本
#! /bin/sh
cd ..
ls
Shell脚本中⽤#表⽰注释,相当于C语⾔的//注释。但如果#位于第⼀⾏开头,并且是#!(称为Shebang)则例外,它表⽰该脚本使⽤后⾯指定的解释器/bin/sh解释执⾏。如果把这个脚本⽂件加上可执⾏权限然后执⾏:
$ chmod +x script.sh
$ ./script.sh
Shell会fork⼀个⼦进程并调⽤exec执⾏./script.sh这个程序,exec系统调⽤应该把⼦进程的代码段替换成./script.sh程序的代码段,并从它
的_start开始执⾏。然⽽script.sh是个⽂本⽂件,根本没有代码段和_start函数,怎么办呢?其实exec还有另外⼀种机制,如果要执⾏的是⼀个⽂本⽂件,并且第⼀⾏⽤Shebang指定了解释器,则⽤解释器程序的代码段替换当前进程,并且从解释器的_start开始执⾏,⽽这个⽂本⽂件被当作命令⾏参数传给解释器。因此,执⾏上述脚本相当于执⾏程序
$ /bin/sh ./script.sh
以这种⽅式执⾏不需要script.sh⽂件具有可执⾏权限。再举个例⼦,⽐如某个sed脚本的⽂件名是script,它的开头是
#! /bin/sed -f
shell最简单脚本执⾏./script相当于执⾏程序
$ /bin/sed -f ./script.sh
以上介绍了两种执⾏Shell脚本的⽅法:
$ ./script.sh
$ sh ./script.sh
这两种⽅法本质上是⼀样的,执⾏上述脚本的步骤为:
图 31.1. Shell脚本的执⾏过程
1. 交互Shell(bash)fork/exec⼀个⼦Shell(sh)⽤于执⾏脚本,⽗进程bash等待⼦进程sh终⽌。
2. sh读取脚本中的cd ..命令,调⽤相应的函数执⾏内建命令,改变当前⼯作⽬录为上⼀级⽬录。
3. sh读取脚本中的ls命令,fork/exec这个程序,列出当前⼯作⽬录下的⽂件,sh等待ls终⽌。
4. ls终⽌后,sh继续执⾏,读到脚本⽂件末尾,sh终⽌。
5. sh终⽌后,bash继续执⾏,打印提⽰符等待⽤户输⼊。
如果将命令⾏下输⼊的命令⽤()括号括起来,那么也会fork出⼀个⼦Shell执⾏⼩括号中的命令,⼀⾏中可以输⼊由分号;隔开的多个命令,⽐如:
$ (cd ..;ls -l)
和上⾯两种⽅法执⾏Shell脚本的效果是相同的,cd ..命令改变的是⼦Shell的PWD,⽽不会影响到交互式Shell。然⽽命令
$ cd ..;ls -l
则有不同的效果,cd ..命令是直接在交互式Shell下执⾏的,改变交互式Shell的PWD,然⽽这种⽅式相当于这样执⾏Shell脚本:
$ source ./script.sh
或者
$ . ./script.sh
source或者.命令是Shell的内建命令,这种⽅式也不会创建⼦Shell,⽽是直接在交互式Shell下逐⾏执⾏脚本中的命令。
习题
1、解释如下命令的执⾏过程:
$ (exit 2)
$ echo $?
2

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。