刚看了apue的关于解析器文件的部分,感受颇多,记录一下吧。
解析器文件是一种文本文件,文件的第一行的形式:#! pathname [optional-argument];
其中pathname指的时解析器名称,optional-argument是传递给解析器的参数。其实我们大家最熟悉的解析器文件就是shell脚本文件,shell脚本文件第一行都是#! /bin/sh。
解析器文件是一种文本文件,而解析器是可执行的二进制文件。解析器是由解析器文件的第一行指定的。
例如一个displayArgTab程序,用于显示执行该程序时的参数表,代码如下:
//name:displayArgTab
int main(int argc, char *argv[])
{
int i;
for(i = 0; i<argc ;i++)
printf("argv[%d]: %s\n", i, argv[i]);
return 0;
}
以displayArgTab为解析器,写一个解析器文件,如下:
//解析器文件名为testInterpreter
#! /tmp/displayArgTab arg
生成的解析器文件testInterpreter也放在/tmp/下。下面通过execl来调用解析器文件:
if(execl("/tmp/testInterpreter", "testInterpreter", "myarg1", "myarg2", (char*)NULL) < 0)
{
printf("execl error...\n");
return 0;
}
执行结果为:
argv[0]: /tmp/displayArgTab
argv[1]: arg
argv[2]: /tmp/testInterpreter
argv[3]: myarg1
argv[4]: myarg2
由此可以得知内核在执行解析器文件时,向解析器传递的参数依次是:
- 解析器的pathname-路径名;
- 解析器的可选参数(如果没有则不会传递);
- exec的解析器文件的pathname-路径名;
- exec的第二个参数;
- exec的第三个参数,......;
有些程序是用脚本语言写的,解释器文件可将这一事实隐藏起来,例如shell脚本,awk脚本。例如下面是一段awk脚本,由awk程序进行解析。
#! /bin/awk -f
BEGIN {
for(i = 0; i < ARGC; i++)
printf "ARGV[%d] = %s\n", i, ARGV[i]
exit
}
上面#!后接的时该解析器文件的解析器awk程序,和解析器的参数-f;下面的脚本程序是按awk语法所写的脚本,功能是显示传递给awk脚本的参数。测试结果如下:
//脚本文件名为testAwk
$ ./testAwk arg1 arg2 arg3
ARGV[0] = awk
ARGV[1] = arg1
ARGV[2] = arg2
ARGV[3] = arg3
在运行文件testAwk时,要赋予x权限。上述执行解析器文件testAwk的过程实际是这样的:
- 首先shell读取这个命令时,首先会认为它是一个机器可执行的文件,即二进制的机器语言,shell会试图execl此文件名,但该文件时一个脚本文件,即文本文件,对于机器来说是不可执行的,所以会返回错误。
- 返回错误后,shell就认为该文件是一个解析器文件(脚本文件)。然后调用该解析器文件的解析器解析脚本文件的内容。
当然上述执行过程可以直接调用解析器文件的解析器来直接运行,如下:
$ awk -f testAwk arg1 arg2 arg3
ARGV[0] = awk
ARGV[1] = arg1
ARGV[2] = arg2
ARGV[3] = arg3
这样执行的效率肯定比直接执行脚本的效率要高,因为省略了上述第一个过程。
欢迎大家批评指正!
Sep 29, 2012 PM 20:28 @lab