分类:
2008-11-26 18:03:11
8.12 interpreter files
本文针对exec和interpreter文件的使用,用例子来检测了参数的传递。
经常看到一些开头是如下格式的脚本文件:
#! /bin/awk -f 等等。
这些文件还都是可执行的,但是他们又不同于linux系统本身的可执行文件的格式。但是都可以在命令行下用./a.out来启动他们,所以他们的执行一定有一个过程。
(一)使用#! xxx
有脚本myscript内容如下:
#!/bin/awk -f
BEGIN {
for (i = 0; i < ARGC; i++)
printf "ARGV[%d] = %s\n", i, ARGV[i]
exit
}
其执行过程我觉得是如下的:
1.你在shell里面敲./myscript arg1 arg2
2.Shell就认为你要执行一个外部命令,所以就fork 出一个子shell A
3.子shellA开始尝试用execlp执行./myscript却出错,因为它不是一个普通的可执行文件格式,于是shell A就认为它是一个脚本。
4.于是子shell A就打开myscrpt, 读取其第一行,发现是#! /bin/awk –f,那么shell就知道了原来这是一个awk脚本,需要由/bin/awk程序去处理,而且应该传递参数-f给awk., 此外还有三个参数,分别是命令本身“./myscrpt”,以及arg0, arg1,这样shell就知道了所有的事情。
5.好了,exec awk吧,参数分别为:/bin/awk, -f, ./myscript, arg0, arg1
其中,/bin/awk是程序本身,注意脚本文件./myscript也成了参数。
你看,你调用了awk去处理文件./myscrpt,那么awk就会打开myscript,此时#!对于awk来说就是一段注释,awk就不会管他了。
总之,一共有一个子进程被fork出来。而且调用这些可执行的脚本的时候,我们没必要去关心究竟由谁去处理它,这些工作是由shell自己完成的。这是脚本的好处。
(二)不使用#! xxx
如果不使用#! /bin/awk –f这一行。比如我们有这样一个可执行文件:
awk 'BEGIN {
for (i = 0; i < ARGC; i++)
printf "ARGV[%d] = %s\n", i, ARGV[i]
exit
}' $*
那么其执行过程如下:
1.你在shell里面敲./myscript arg1 arg2
2.Shell就认为你要执行一个外部命令,所以就fork 出一个子shell A
3.子shellA开始尝试用execlp执行./myscript却出错,因为它不是一个普通的可执行文件格式,于是shell A就认为它是一个脚本。
4. shell A打开这个文件,也没看到啥东西,直接上来就是awk ‘BEGIN’ { …..,多以对于这个shell来说你是在调用外部命令awk,所以,他怎会怎么做呢?
5. shell A 会fork一个子shell,然后在子shell里执行exec awk,参数呢就是/bin/awk, 以及你在这个脚本里调用awk时提供的参数,如果你想将脚本的参数arg1, arg2也传递给awk,就必须在脚本内部利用shell变量$1, $2显式作为传给awk的参数。而如果我们使用了#! Xxx,那么我们调用脚本时的参数就传给了awk本身,当然也包括脚本文件本身。
总之,如果不在一个脚本前加上#! Xxx,那么整体执行下来,需要多做一次fork,可见开销较大。
其实第一个脚本使用#! /bini/awk是一个awk脚本,第2个不使用#!/bin/awk的脚本是一个shell脚本。可见使用shell脚本不如直接使用awk脚本效率高啊。
为了测试,写了个例子,如下:
(例子1)
1.我们写了一个自己的名为awk的程序用来代替系统的awk:,好做测试。
这个程序仅仅是打印自己的参数。
#include
int main( int argc, char* argv[] )
{
printf("in awk %d args:\n", argc );
for( int i=0; i
{
printf("arg[%d]=", i);
puts( argv[i] );
}
}
2.然后将此程序编译成awk,然后覆盖/usr/bin/awk目录。
3.然后系一个脚本myscript内容如下:
#! /usr/bin/awk –f
可见仅有一句话,它的目的就是调用 awk程序。
4.我们的执行流程如下:
shaoting@desktopbj-LabSD:/home/shaoting/mytest> ./myscript2 222
in awk 4 args:
arg[0]=/usr/bin/awk
arg[1]=-f
arg[2]=./myscript2
arg[3]=222
可见,我们提供给脚本的参数也成了调用awk的参数
(例子2)
1.依然使用上边的awk
2. 我们的脚本myscript2内容如下:
echo $0
echo $1
echo $2
awk -f 'kkak'
3. 执行流程如下:
shaoting@desktopbj-LabSD:/home/shaoting/mytest> ./myscript arg0 arg1
./myscript
arg0
arg1
in awk 3 args:
arg[0]=awk
arg[1]=-f
arg[2]=kkak
可见,在脚本内,$0, $1,$2对应的就是./myscript, arg0, arg1,他们仅仅是脚本的参数
而awk输出的参数里,只有awk, -f , kkak即我们在脚本里调用awk时候的参数,而并不包括脚本的参数。
(例子三)这个例子是仿照书上的写的
(1)Myscript3的内容如下:
#! /usr/bin/awk -f
BEGIN {
for(i=0; i
printf "
arg[%d]=%s\n" , i, ARGV[i]
exit
}
执行流程:
shaoting@desktopbj-LabSD:/home/shaoting/mytest> ./myscript3 arg0 arg1
in awk 5 args:
arg[0]=/usr/bin/awk
arg[1]=-f
arg[2]=./myscript3
arg[3]=arg0
arg[4]=arg1
(2) myscript4的内容如下
awk 'BEGIN {
for(i=0; i
printf "
arg[%d]=%s\n" , i, ARGV[i]
exit
}' $*
执行流程:(注意,$*并不包括”./myscript
shaoting@desktopbj-LabSD:/home/shaoting/mytest> ./myscript4 arg0 arg1
in awk 4 args:
arg[0]=awk
arg[1]=BEGIN {
for(i=0; i
printf "
arg[%d]=%s\n" , i, ARGV[i]
exit
}
arg[2]=arg0
arg[3]=arg1
总之,interpreter file的优点:
1.可以隐藏究竟要用哪个解释器来执行这个脚本
2.效率比使用shell脚本高,因为减少了fork
3.可以使用不同的shell来处理脚本,比如我们可以在csh和bash之间做出选择。更灵活。