解释器文件

解释器文件是一种文本文件,其起始行的形式是:
#! pathname [optional-argument]
其中感叹号和 pathname 之间的空格是可选的。pathname 通常是绝对路径名,对它不进行什么特殊处理(不使用 PATH 进行路径搜索),它后面的参数(如果有)无论多少都会被作为一个参数来对待。对这种文件的识别是由内核作为 exec 系统调用处理的一部分来完成的。内核使调用 exec 函数的进程实际执行的并不是该解释器文件,而是 pathname 所指定的解释器。
很多系统对解释器文件的第一行都有长度限制,比如 Linux 3.2.0 中该限制为 128 字节。
下面这个程序 interFileDemo.out 调用 exec 执行一个解释器文件,演示了当被执行的文件是个解释器文件时,内核如何处理 exec 函数的参数以及该解释器文件第一行的可选参数。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

int main(void){
pid_t pid;
if((pid=fork()) < 0){
printf("fork error\n");
exit(2);
}
if(pid == 0){
if(execl("./testInterp", "testInterp", "arg1", "arg2", (char *)0) < 0){
printf("execl error\n");
exit(2);
}
}
if(waitpid(pid, NULL, 0) < 0){
printf("waitpid error\n");
exit(2);
}
exit(0);
}

这里的解释器文件“./testInterp”只有一行内容:
/home/me/bin/echoarg foo bar
而它所指定的解释器 echoarg 的源代码如下。

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]){
int i;
for(i=0; i<argc; i++)
printf("argv[%d]: %s\n", i, argv[i]);
exit(0);
}

运行结果如下(这 3 个文件都需要有执行权限):

$ ./interFileDemo.out
argv[0]: /home/me/bin/echoarg
argv[1]: foo bar # 这里把它们都合并成一个参数了
argv[2]: ./testInterp # 取的是 exec 调用中的 pathname,而非 arg0
argv[3]: arg1
argv[4]: arg2

在解释器 pathname 后可跟随可选参数,比如 awk(1) 程序支持“awk -f myfile”,它告诉 awk 从文件 myfile 中读 awk 程序,在解释器文件中可以写成:
#!/bin/awk -f
比如下面这个关于 awk 的解释器文件程序 awkexample。

#!/usr/bin/awk -f
# Note: on Solaris, use nawk instead
BEGIN{
for(i=0; i<ARGC; i++)
printf "ARGV[%d] = %s\n", i, ARGV[i]
exit
}

执行该程序得到如下结果:

$ ./awkexample file filename2 f3
ARGV[0] = awk
ARGV[1] = file
ARGV[2] = filename2
ARGV[3] = f3

执行 /bin/awk 时,其命令行参数是:
/bin/awk -f ./awkexample file filename2 f3
可用下列命令验证上述命令行参数。

$ /bin/su
密码:
# mv /usr/bin/awk /usr/bin/awk.save
# cp ./echoarg /usr/bin/awk
# suspend # 用作业控制挂起超级用户 shell
[1]+ Stopped /bin/su
$
$ ./awkexample file filename2 f3 # 这时的 /usr/bin/awk 实际上是 echoarg
argv[0]: /usr/bin/awk
argv[1]: -f
argv[2]: ./awkexample
argv[3]: file
argv[4]: filename2
argv[5]: f3
$
$ fg
/bin/su
$ mv -f /usr/bin/awk.save /usr/bin/awk
# exit
$

注意,如果不能向解释器传递可选参数,那么该解释器文件只有对 shell 才是有用的。
解释器文件可使用户得到效率方面的好处,代价是内核的额外开销(因为是内核识别接解释器文件)。由于下述理由,解释器文件是有用的。
1、隐藏程序的编写语言。比如要执行上面的 awkexample 程序,只需要使用命令:
./awkexample optional-arguments
而没必要知道该程序是一个 awk 脚本,否则就需要以下列方式执行程序:
awk -f awkexample optional-arguments
2、解释器脚本在效率方面也提供了好处。假设将上面的 awkexample 代码放在一个普通 shell 脚本中:

awk 'BEGIN{
for(i=0; i<ARGC; i++)
printf "ARGV[%d] = %s\n", i, ARGV[i]
exit
}' $*

这种方法将会做更多的工作。首先,shell 读此命令,然后试图 execlp 此文件名。因为 shell 脚本是一个可执行文件,但却不是机器可执行的,于是返回一个错误,execlp 就认为该文件是一个 shell 脚本(它实际上就是),然后执行 /bin/sh,并以该 shell 脚本的路径名作为其参数。尽管 shell 能正确地执行这个 shell 脚本,但是为了运行 awk 程序,它会调用 fork、exec 和 wait,所以用一个 shell 脚本代替解释器脚本需要更多的开销。
3、解释器脚本使我们可以使用 /bin/sh 以外的其他 shell 来编写 shell 脚本。当 execlp 找到一个非机器可执行的可执行文件时,它总是调用 /bin/sh 来解释执行该文件。而用解释器脚本则可简单地使用“#!/bin/csh”之类的来代替。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值