Wednesday, September 24, 2014

Unix Prog: Interpreter Files

1. Introduction

When system run the interpreter file, it will run the first line's program + interpreter file, instead of running interpreter file itself.

 ubuntu@ip-172-31-23-227:~$ cat ./ifile  
 #! /bin/echo  
 ubuntu@ip-172-31-23-227:~$ ./ifile  
 ./ifile  

In above example, when ./ifile get executed, system actually run:
/bin/echo ./ifile

That's why we have above output.

Note: system has size limits of the first line of interpreter file.

2. Example

echoall.c:
 #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);  
 }  

testIntScript:
 #! /home/ubuntu/echoall.out foo bar  

testint.c:
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<sys/wait.h>  
 #include<unistd.h>  
   
 int main(int argc, char* argv[])  
 {  
  pid_t pid;  
  if((pid = fork()) < 0) {  
   printf("fork error!\n");  
   exit(1);  
  }  
  else if (pid == 0) {  
   if(execl("/home/ubuntu/testIntScript", "First arg", "Second Arg", (char*)0) < 0) {  
    printf("execl error!\n");  
    exit(2);  
   }  
  }  
   
  if(waitpid(pid, NULL, 0) < 0) {  
   printf("waitpid error!\n");  
   exit(3);  
  }  
   
  exit(0);  
 }  

shell:
Note: when calling the execl, the 1st arg is the interpreter file itself, 2nd arg is "all optional arguments"(foo bar), third arg is the script file, remaining arguments are from "Second Arg", "First arg" is ignored in this case.

So the real command getting run in this case is:
/home/ubuntu/echoall.out "foo bar" /home/ubuntu/testIntScript "Second Arg"
 ubuntu@ip-172-31-23-227:~$ ./testint.out  
 argv[0]: /home/ubuntu/echoall.out  
 argv[1]: foo bar  
 argv[2]: /home/ubuntu/testIntScript  
 argv[3]: Second Arg  

3. awk

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

shell:
The actual command getting run is :
/usr/bin/awk -f ./awkscript Hello world!
So it will have following output.
 ubuntu@ip-172-31-23-227:~$ ./awkscript Hello world!  
 ARGV[0] = awk  
 ARGV[1] = Hello  
 ARGV[2] = world!  

Efficiency gain with interpreter file, compared to following file:
awkShell:
 awk 'BEGIN {  
   for (i = 0; i < ARGC; i++)  
    printf "ARGV[%d] = %s\n", i, ARGV[i]  
    exit  
 }' $*  

shell:
Shell will firstly use execl to run the file "./awkShell", but it is not machine executable file. And then, it will turn to use the "/bin/sh" to run the file, with fork, exec and exit. Compared to interpreter file, it has more overhead time cost.
 ubuntu@ip-172-31-23-227:~$ ./awkShell Hello world!  
 ARGV[0] = awk  
 ARGV[1] = Hello  
 ARGV[2] = world!  

No comments:

Post a Comment